<commit_before>#include "SymmAnisotropicElasticityTensor.h"
#include <cmath>
#include <ostream>

SymmAnisotropicElasticityTensor::SymmAnisotropicElasticityTensor()
  : SymmElasticityTensor(false),
    _dmat(9,9),
    _qdmat(9,9),
    _dt(6,6),
    _qdt(6,6),
    _r(3,3),
    _q(9,9),
    _qt(9,9),
    _euler_angle(3),
    _trans_d6_to_d9(9,6),
    //_transpose_trans_d6_to_d9(6,9),
    _trans_d9_to_d6(6,9),
    //_transpose_trans_d9_to_d6(9,6),
    _c11(0),
    _c12(0),
    _c44(0)
{
  //form_transformation_t_matrix();
}

SymmAnisotropicElasticityTensor::SymmAnisotropicElasticityTensor(std::vector<Real> & init_list, bool all_21)
    : SymmElasticityTensor(false),
      _dmat(9,9),
      _qdmat(9,9),
      _dt(6,6),
      _qdt(6,6),
      _r(3,3),
      _q(9,9),
      _qt(9,9),
      _euler_angle(3),
      _trans_d6_to_d9(9,6),
      //_transpose_trans_d6_to_d9(6,9),
      _trans_d9_to_d6(6,9),
      //_transpose_trans_d9_to_d6(9,6),
      _c11(0),
      _c12(0),
      _c44(0)
{
// test the input vector length to make sure it's correct
  if ((all_21==true && init_list.size()!=21) ||(all_21==false && init_list.size()!=9) )
    mooseError("Please correct the number of entries in the stiffness input.");

  if(all_21 == true)
  {
    for (int i = 0; i < 21; i++)
      _val[i] = init_list[i];
  }
  else
  {
    _val[0] = init_list[0];   //C1111
    _val[1] = init_list[1];   //C1122
    _val[2] = init_list[2];   //C1133
    _val[6] = init_list[3];   //C2222
    _val[7] = init_list[4];   //C2233
    _val[11] = init_list[5];  //C3333
    _val[15] = init_list[6];  //C2323
    _val[18] = init_list[7];  //C1313
    _val[20] = init_list[8];  //C1212
  }

  //form_transformation_t_matrix();
}

SymmAnisotropicElasticityTensor::SymmAnisotropicElasticityTensor(const SymmAnisotropicElasticityTensor & a)
     : SymmElasticityTensor(false)
 {
   *this = a;
 }

void SymmAnisotropicElasticityTensor::setFirstEulerAngle(const Real a1)
{
  _euler_angle[0] = a1;
}

void SymmAnisotropicElasticityTensor::setSecondEulerAngle(const Real a2)
{
  _euler_angle[1] = a2;
}

void SymmAnisotropicElasticityTensor::setThirdEulerAngle(const Real a3)
{
  _euler_angle[2] = a3;
}

Real
SymmAnisotropicElasticityTensor::firstEulerAngle()
{
  return _euler_angle[0];
}

Real
SymmAnisotropicElasticityTensor::secondEulerAngle()
{
  return _euler_angle[1];
}

Real
SymmAnisotropicElasticityTensor::thirdEulerAngle()
{
  return _euler_angle[2];
}

void SymmAnisotropicElasticityTensor::setMaterialConstantc11(const Real c11)
{
  _c11 = c11;
  _val[0] = _val[6] = _val[11] = _c11;
}

void SymmAnisotropicElasticityTensor::setMaterialConstantc12(const Real c12)
{
  _c12 = c12;
  _val[1] = _val[2] = _val[7] = _c12;
}

void SymmAnisotropicElasticityTensor::setMaterialConstantc44(const Real c44)
{
  _c44 = c44;
  _val[15] = _val[18] = _val[20] = _c44;
}

void
SymmAnisotropicElasticityTensor::rotate(const Real a1, const Real a2, const Real a3)
{
  setFirstEulerAngle(a1);
  setSecondEulerAngle(a2);
  setThirdEulerAngle(a3);

  // pulled from calculateEntries to sub in the initialize_anisotropic_material_dt_matrix() call
  calculateEntries(0);
}

void SymmAnisotropicElasticityTensor::form_r_matrix()
{
  Real phi1 = _euler_angle[0] * (libMesh::pi/180.0);
  Real phi = _euler_angle[1] * (libMesh::pi/180.0);
  Real phi2 = _euler_angle[2] * (libMesh::pi/180.0);

  Real cp1 = std::cos(phi1);
  Real cp2 = std::cos(phi2);
  Real cp = std::cos(phi);

  Real sp1 = std::sin(phi1);
  Real sp2 = std::sin(phi2);
  Real sp = std::sin(phi);

  _r(0,0) = cp1 * cp2 - sp1 * sp2 * cp;
  _r(0,1) = sp1 * cp2 + cp1 * sp2 * cp;
  _r(0,2) = sp2 * sp;
  _r(1,0) = -cp1 * sp2 - sp1 * cp2 * cp;
  _r(1,1) = -sp1 * sp2 + cp1 * cp2 * cp;
  _r(1,2) = cp2 * sp;
  _r(2,0) = sp1 * sp;
  _r(2,1) = -cp1 * sp;
  _r(2,2) = cp;
}

// this is now obsolete
void
SymmAnisotropicElasticityTensor::initialize_material_dt_matrix()
{
// This function initializes the 6 x 6 material Dt matrix for a cubic material

  _dt(0,0) = _dt(1,1) = _dt(2,2) = _c11;
  _dt(0,1) = _dt(0,2) = _dt(1,0) = _dt(2,0) = _dt(1,2) = _dt(2,1) = _c12;
  // beware the factor of two here
  _dt(3,3) = _dt(4,4) = _dt(5,5) = 2 * _c44;
}

// this is now obsolete
void
SymmAnisotropicElasticityTensor::initialize_anisotropic_material_dt_matrix()
{
// This function initializes the 6 x 6 material Dt matrix for an anisotropic material

  int k = 0;
  for (int i=0; i<6; i++)
  {
    for (int j=i; j<6; j++)
    {
      _dt(i,j) = _dt(j,i) = _val[k++];
    }
  }
}

void
SymmAnisotropicElasticityTensor::form_rotational_q_matrix()
{

  for(int i = 0; i < 3; ++i)
    for(int j = 0; j < 3; ++j)
      for (int k = 0; k < 3; ++k)
        for(int l = 0; l < 3; ++l)
          _q(((i*3)+k),((j*3)+l)) = _r(i,j) * _r(k,l);

/*for(int p = 0; p < 9; ++p)
  for(int q = 0; q < 9; ++q)
  _qt(q,p) = _q(p,q);*/
}

void
SymmAnisotropicElasticityTensor::form_transformation_t_matrix()
{
  // Forms to two kinds of transformation matrix
  // TransD6toD9 transfroms Dt[6][6] to Dmat[9][9]
  // TransD9toD6 transforms Dmat[9][9] to Dt[6][6]

  Real sqrt2 = std::sqrt(2.0);
//  Real a = 1/sqrt2;
  Real a = 1.0;

  _trans_d6_to_d9(0,0) = _trans_d6_to_d9(4,1) =  _trans_d6_to_d9(8,2) = 1.0;
  _trans_d6_to_d9(1,3) = _trans_d6_to_d9(3,3) = a;
  _trans_d6_to_d9(5,4) = _trans_d6_to_d9(7,4) = a;
  _trans_d6_to_d9(2,5) = _trans_d6_to_d9(6,5) = a;

  /*for(int i = 0; i < 9; ++i)
  {
    for(int j = 0; j < 6; ++j)
    {
      _transpose_trans_d6_to_d9(j,i) = _trans_d6_to_d9(i,j);
    }
    }*/

  _trans_d9_to_d6(0,0) = _trans_d9_to_d6(1,4) =  _trans_d9_to_d6(2,8) = 1.0;
//  _trans_d9_to_d6(3,3) = _trans_d9_to_d6(4,7) =  _trans_d9_to_d6(5,6) = sqrt2;
  _trans_d9_to_d6(3,3) = _trans_d9_to_d6(4,7) =  _trans_d9_to_d6(5,6) = 1.0;

  /*for(int i = 0; i < 6; ++i)
  {
    for(int j = 0; j < 9; ++j)
    {
      _transpose_trans_d9_to_d6(j,i) =  _trans_d9_to_d6(i,j);
    }
    }*/

}

void SymmAnisotropicElasticityTensor::form_transformed_material_dmat_matrix()
{

  // THIS TRANSFORMATION IS VALID ONLY WHEN THE INCOMING MATRIX HAS NOT BEEN ROTATED

  // The function makes use of TransD6toD9 matrix to transfrom
  // Dt[6][6] to Dmat[9][9]
  // Dmat = T * Dt * TT

  //DenseMatrix<Real> outputMatrix(9,6);

  //outputMatrix = _trans_d6_to_d9;
  //outputMatrix.right_multiply(_dt);

  //_dmat = outputMatrix;
  //_dmat.right_multiply_transpose(_trans_d6_to_d9);

  // Use the plug-and-chug functions given in SymmElasticityTensor
  // to take the existing _val[] and put them into the 9x9 _dmat matrix.
  SymmElasticityTensor temp_dt;
  copyValues(temp_dt);

  ColumnMajorMatrix temp_dmat = temp_dt.columnMajorMatrix9x9();

  for (unsigned j(0); j < 9; ++j)
  {
    for (unsigned i(0); i < 9; ++i)
    {
      _dmat(i,j) = temp_dmat(i,j);
    }
  }
}

void SymmAnisotropicElasticityTensor::form_transformed_material_dt_matrix()
{
  // The function makes use of TransD6toD9 matrix to transfrom
  // QDmat[9][9] to Dt[6][6]
  // Dt = TT * QDmat * T

//   DenseMatrix<Real> outputMatrix(6,9);

//   outputMatrix = _trans_d9_to_d6;
//   outputMatrix.right_multiply(_qdmat);
//   _dt = outputMatrix;
//   _dt.right_multiply(_transpose_trans_d9_to_d6);

  // The transformation below is general and should work whether or not the
  //   incoming tensor has been rotated.

  ColumnMajorMatrix tmp(9,9);
  for (unsigned j(0); j < 9; ++j)
  {
    for (unsigned i(0); i < 9; ++i)
    {
      tmp(i,j) = _qdmat(i,j);
    }
  }

  SymmElasticityTensor fred;
  fred.convertFrom9x9( tmp );
  ColumnMajorMatrix wilma = fred.columnMajorMatrix6x6();
  for (unsigned j(0); j < 6; ++j)
  {
    for (unsigned i(0); i < 6; ++i)
    {
      _dt(i,j) = wilma(i,j);
    }
  }
}

void
SymmAnisotropicElasticityTensor::form_rotated_material_qdmat_matrix()
{
 // The function makes use of Q matrix to rotate
  // Dmat[9][9] to QDmat[9][9]
  // QDmat = QT * Dmat * Q

  DenseMatrix<Real> outputMatrix(9,9);

  _q.get_transpose(outputMatrix);
  outputMatrix.right_multiply(_dmat);

  _qdmat = outputMatrix;
  _qdmat.right_multiply(_q);
}

void
SymmAnisotropicElasticityTensor::calculateEntries(unsigned int /*qp*/)
{
  form_r_matrix();
  //initialize_material_anisotropic_dt_matrix();
  form_rotational_q_matrix();
  // form_transformation_t_matrix();
  form_transformed_material_dmat_matrix();
  form_rotated_material_qdmat_matrix();
  form_transformed_material_dt_matrix();

  unsigned count(0);

  for (int j(0); j < 6; ++j)
  {
    for(int i(j); i < 6; ++i)
    {
      _val[count++] = _dt(i,j);
    }
  }
}

void
SymmAnisotropicElasticityTensor::show_dt_matrix()
{
  printf("\nSymmAnisotropicElasticityTensor::show_dt_matrix()\n");

  for (int j = 0; j < 6; ++j)
  {
    printf("  ");
    for(int i = 0; i < 6; ++i)
    {
      printf("%12.4f  ", _dt(i,j));
    }
    printf("\n");
  }
}

void
SymmAnisotropicElasticityTensor::show_r_matrix()
{
  printf("\nSymmAnisotropicElasticityTensor::show_r_matrix()  Euler angles are (%f, %f, %f)\n",
	 _euler_angle[0], _euler_angle[1], _euler_angle[2]);

  for (int j = 0; j < 3; ++j)
  {
    printf("  ");
    for(int i = 0; i < 3; ++i)
    {
      printf("%8.4f  ", _r(i,j));
    }
    printf("\n");
  }
}
<commit_msg>Fixing brain damage in SymmAnisotropicElasticityTensor<commit_after>#include "SymmAnisotropicElasticityTensor.h"
#include <cmath>
#include <ostream>

SymmAnisotropicElasticityTensor::SymmAnisotropicElasticityTensor()
  : SymmElasticityTensor(false),
    _dmat(9,9),
    _qdmat(9,9),
    _dt(6,6),
    _qdt(6,6),
    _r(3,3),
    _q(9,9),
    _qt(9,9),
    _euler_angle(3),
    _trans_d6_to_d9(9,6),
    //_transpose_trans_d6_to_d9(6,9),
    _trans_d9_to_d6(6,9),
    //_transpose_trans_d9_to_d6(9,6),
    _c11(0),
    _c12(0),
    _c44(0)
{
  //form_transformation_t_matrix();
}

SymmAnisotropicElasticityTensor::SymmAnisotropicElasticityTensor(std::vector<Real> & init_list, bool all_21)
    : SymmElasticityTensor(false),
      _dmat(9,9),
      _qdmat(9,9),
      _dt(6,6),
      _qdt(6,6),
      _r(3,3),
      _q(9,9),
      _qt(9,9),
      _euler_angle(3),
      _trans_d6_to_d9(9,6),
      //_transpose_trans_d6_to_d9(6,9),
      _trans_d9_to_d6(6,9),
      //_transpose_trans_d9_to_d6(9,6),
      _c11(0),
      _c12(0),
      _c44(0)
{
// test the input vector length to make sure it's correct
  if ((all_21==true && init_list.size()!=21) ||(all_21==false && init_list.size()!=9) )
    mooseError("Please correct the number of entries in the stiffness input.");

  if(all_21 == true)
  {
    for (int i = 0; i < 21; i++)
      _val[i] = init_list[i];
  }
  else
  {
    _val[0] = init_list[0];   //C1111
    _val[1] = init_list[1];   //C1122
    _val[2] = init_list[2];   //C1133
    _val[6] = init_list[3];   //C2222
    _val[7] = init_list[4];   //C2233
    _val[11] = init_list[5];  //C3333
    _val[15] = init_list[6];  //C2323
    _val[18] = init_list[7];  //C1313
    _val[20] = init_list[8];  //C1212
  }

  //form_transformation_t_matrix();
}

SymmAnisotropicElasticityTensor::SymmAnisotropicElasticityTensor(const SymmAnisotropicElasticityTensor & a)
     : SymmElasticityTensor(false)
 {
   *this = a;
 }

void SymmAnisotropicElasticityTensor::setFirstEulerAngle(const Real a1)
{
  _euler_angle[0] = a1;
}

void SymmAnisotropicElasticityTensor::setSecondEulerAngle(const Real a2)
{
  _euler_angle[1] = a2;
}

void SymmAnisotropicElasticityTensor::setThirdEulerAngle(const Real a3)
{
  _euler_angle[2] = a3;
}

Real
SymmAnisotropicElasticityTensor::firstEulerAngle()
{
  return _euler_angle[0];
}

Real
SymmAnisotropicElasticityTensor::secondEulerAngle()
{
  return _euler_angle[1];
}

Real
SymmAnisotropicElasticityTensor::thirdEulerAngle()
{
  return _euler_angle[2];
}

void SymmAnisotropicElasticityTensor::setMaterialConstantc11(const Real c11)
{
  _c11 = c11;
  _val[0] = _val[6] = _val[11] = _c11;
}

void SymmAnisotropicElasticityTensor::setMaterialConstantc12(const Real c12)
{
  _c12 = c12;
  _val[1] = _val[2] = _val[7] = _c12;
}

void SymmAnisotropicElasticityTensor::setMaterialConstantc44(const Real c44)
{
  _c44 = c44;
  _val[15] = _val[18] = _val[20] = _c44;
}

void
SymmAnisotropicElasticityTensor::rotate(const Real a1, const Real a2, const Real a3)
{
  setFirstEulerAngle(a1);
  setSecondEulerAngle(a2);
  setThirdEulerAngle(a3);

  // pulled from calculateEntries to sub in the initialize_anisotropic_material_dt_matrix() call
  calculateEntries(0);
}

void SymmAnisotropicElasticityTensor::form_r_matrix()
{
  Real phi1 = _euler_angle[0] * (libMesh::pi/180.0);
  Real phi = _euler_angle[1] * (libMesh::pi/180.0);
  Real phi2 = _euler_angle[2] * (libMesh::pi/180.0);

  Real cp1 = std::cos(phi1);
  Real cp2 = std::cos(phi2);
  Real cp = std::cos(phi);

  Real sp1 = std::sin(phi1);
  Real sp2 = std::sin(phi2);
  Real sp = std::sin(phi);

  _r(0,0) = cp1 * cp2 - sp1 * sp2 * cp;
  _r(0,1) = sp1 * cp2 + cp1 * sp2 * cp;
  _r(0,2) = sp2 * sp;
  _r(1,0) = -cp1 * sp2 - sp1 * cp2 * cp;
  _r(1,1) = -sp1 * sp2 + cp1 * cp2 * cp;
  _r(1,2) = cp2 * sp;
  _r(2,0) = sp1 * sp;
  _r(2,1) = -cp1 * sp;
  _r(2,2) = cp;
}

// this is now obsolete
void
SymmAnisotropicElasticityTensor::initialize_material_dt_matrix()
{
// This function initializes the 6 x 6 material Dt matrix for a cubic material

  _dt(0,0) = _dt(1,1) = _dt(2,2) = _c11;
  _dt(0,1) = _dt(0,2) = _dt(1,0) = _dt(2,0) = _dt(1,2) = _dt(2,1) = _c12;
  // beware the factor of two here
  _dt(3,3) = _dt(4,4) = _dt(5,5) = 2 * _c44;
}

// this is now obsolete
void
SymmAnisotropicElasticityTensor::initialize_anisotropic_material_dt_matrix()
{
// This function initializes the 6 x 6 material Dt matrix for an anisotropic material

  int k = 0;
  for (int i=0; i<6; i++)
  {
    for (int j=i; j<6; j++)
    {
      _dt(i,j) = _dt(j,i) = _val[k++];
    }
  }
}

void
SymmAnisotropicElasticityTensor::form_rotational_q_matrix()
{

  for(int i = 0; i < 3; ++i)
    for(int j = 0; j < 3; ++j)
      for (int k = 0; k < 3; ++k)
        for(int l = 0; l < 3; ++l)
          _q(((i*3)+k),((j*3)+l)) = _r(i,j) * _r(k,l);

/*for(int p = 0; p < 9; ++p)
  for(int q = 0; q < 9; ++q)
  _qt(q,p) = _q(p,q);*/
}

void
SymmAnisotropicElasticityTensor::form_transformation_t_matrix()
{
  // Forms to two kinds of transformation matrix
  // TransD6toD9 transfroms Dt[6][6] to Dmat[9][9]
  // TransD9toD6 transforms Dmat[9][9] to Dt[6][6]

  Real sqrt2 = std::sqrt(2.0);
//  Real a = 1/sqrt2;
  Real a = 1.0;

  _trans_d6_to_d9(0,0) = _trans_d6_to_d9(4,1) =  _trans_d6_to_d9(8,2) = 1.0;
  _trans_d6_to_d9(1,3) = _trans_d6_to_d9(3,3) = a;
  _trans_d6_to_d9(5,4) = _trans_d6_to_d9(7,4) = a;
  _trans_d6_to_d9(2,5) = _trans_d6_to_d9(6,5) = a;

  /*for(int i = 0; i < 9; ++i)
  {
    for(int j = 0; j < 6; ++j)
    {
      _transpose_trans_d6_to_d9(j,i) = _trans_d6_to_d9(i,j);
    }
    }*/

  _trans_d9_to_d6(0,0) = _trans_d9_to_d6(1,4) =  _trans_d9_to_d6(2,8) = 1.0;
//  _trans_d9_to_d6(3,3) = _trans_d9_to_d6(4,7) =  _trans_d9_to_d6(5,6) = sqrt2;
  _trans_d9_to_d6(3,3) = _trans_d9_to_d6(4,7) =  _trans_d9_to_d6(5,6) = 1.0;

  /*for(int i = 0; i < 6; ++i)
  {
    for(int j = 0; j < 9; ++j)
    {
      _transpose_trans_d9_to_d6(j,i) =  _trans_d9_to_d6(i,j);
    }
    }*/

}

void SymmAnisotropicElasticityTensor::form_transformed_material_dmat_matrix()
{

  // THIS TRANSFORMATION IS VALID ONLY WHEN THE INCOMING MATRIX HAS NOT BEEN ROTATED

  // The function makes use of TransD6toD9 matrix to transfrom
  // Dt[6][6] to Dmat[9][9]
  // Dmat = T * Dt * TT

  //DenseMatrix<Real> outputMatrix(9,6);

  //outputMatrix = _trans_d6_to_d9;
  //outputMatrix.right_multiply(_dt);

  //_dmat = outputMatrix;
  //_dmat.right_multiply_transpose(_trans_d6_to_d9);

  // Use the plug-and-chug functions given in SymmElasticityTensor
  // to take the existing _val[] and put them into the 9x9 _dmat matrix.
  SymmElasticityTensor temp_dt;
  copyValues(temp_dt);

  ColumnMajorMatrix temp_dmat = temp_dt.columnMajorMatrix9x9();

  for (unsigned j(0); j < 9; ++j)
  {
    for (unsigned i(0); i < 9; ++i)
    {
      _dmat(i,j) = temp_dmat(i,j);
    }
  }
}

void SymmAnisotropicElasticityTensor::form_transformed_material_dt_matrix()
{
  // The function makes use of TransD6toD9 matrix to transfrom
  // QDmat[9][9] to Dt[6][6]
  // Dt = TT * QDmat * T

//   DenseMatrix<Real> outputMatrix(6,9);

//   outputMatrix = _trans_d9_to_d6;
//   outputMatrix.right_multiply(_qdmat);
//   _dt = outputMatrix;
//   _dt.right_multiply(_transpose_trans_d9_to_d6);

  // The transformation below is general and should work whether or not the
  //   incoming tensor has been rotated.

  ColumnMajorMatrix tmp(9,9);
  for (unsigned j(0); j < 9; ++j)
  {
    for (unsigned i(0); i < 9; ++i)
    {
      tmp(i,j) = _qdmat(i,j);
    }
  }

  SymmElasticityTensor fred;
  fred.convertFrom9x9( tmp );
  ColumnMajorMatrix wilma = fred.columnMajorMatrix6x6();
  for (unsigned j(0); j < 6; ++j)
  {
    for (unsigned i(0); i < 6; ++i)
    {
      _dt(i,j) = wilma(i,j);
    }
  }
}

void
SymmAnisotropicElasticityTensor::form_rotated_material_qdmat_matrix()
{
 // The function makes use of Q matrix to rotate
  // Dmat[9][9] to QDmat[9][9]
  // QDmat = QT * Dmat * Q

  DenseMatrix<Real> outputMatrix(9,9);

  _q.get_transpose(outputMatrix);
  outputMatrix.right_multiply(_dmat);

  _qdmat = outputMatrix;
  _qdmat.right_multiply(_q);
}

void
SymmAnisotropicElasticityTensor::calculateEntries(unsigned int /*qp*/)
{
  zero();
  setMaterialConstantc11(_c11);
  setMaterialConstantc12(_c12);
  setMaterialConstantc44(_c44);

  form_r_matrix();
  //initialize_material_anisotropic_dt_matrix();
  form_rotational_q_matrix();
  // form_transformation_t_matrix();
  form_transformed_material_dmat_matrix();
  form_rotated_material_qdmat_matrix();
  form_transformed_material_dt_matrix();

  unsigned count(0);

  for (int j(0); j < 6; ++j)
  {
    for(int i(j); i < 6; ++i)
    {
      _val[count++] = _dt(i,j);
    }
  }
}

void
SymmAnisotropicElasticityTensor::show_dt_matrix()
{
  printf("\nSymmAnisotropicElasticityTensor::show_dt_matrix()\n");

  for (int j = 0; j < 6; ++j)
  {
    printf("  ");
    for(int i = 0; i < 6; ++i)
    {
      printf("%12.4f  ", _dt(i,j));
    }
    printf("\n");
  }
}

void
SymmAnisotropicElasticityTensor::show_r_matrix()
{
  printf("\nSymmAnisotropicElasticityTensor::show_r_matrix()  Euler angles are (%f, %f, %f)\n",
	 _euler_angle[0], _euler_angle[1], _euler_angle[2]);

  for (int j = 0; j < 3; ++j)
  {
    printf("  ");
    for(int i = 0; i < 3; ++i)
    {
      printf("%8.4f  ", _r(i,j));
    }
    printf("\n");
  }
}
<|endoftext|>


<commit_before><commit_msg>fix issue 650 for develop (#671)<commit_after><|endoftext|>


<commit_before>/*
  This file is part of the PhantomJS project from Ofi Labs.

  Copyright (C) 2011 Ariya Hidayat <ariya.hidayat@gmail.com>
  Copyright (C) 2011 execjosh, http://execjosh.blogspot.com

  Redistribution and use in source and binary forms, with or without
  modification, are permitted provided that the following conditions are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of the <organization> nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include "config.h"

#include <QDir>
#include <QWebPage>
#include <QWebFrame>
#include <QNetworkProxy>

#include "terminal.h"
#include "utils.h"

// public:
Config::Config(QObject *parent)
    : QObject(parent)
{
    resetToDefaults();
}

void Config::init(const QStringList *const args)
{
    resetToDefaults();

    processArgs(*args);
}

void Config::processArgs(const QStringList &args)
{
    QStringListIterator it(args);
    while (it.hasNext()) {
        const QString &arg = it.next();

        if (arg == "--version") {
            setVersionFlag(true);
            return;
        }
        if (arg == "--load-images=yes") {
            setAutoLoadImages(true);
            continue;
        }
        if (arg == "--load-images=no") {
            setAutoLoadImages(false);
            continue;
        }
        if (arg == "--load-plugins=yes") {
            setPluginsEnabled(true);
            continue;
        }
        if (arg == "--load-plugins=no") {
            setPluginsEnabled(false);
            continue;
        }
        if (arg == "--disk-cache=yes") {
            setDiskCacheEnabled(true);
            continue;
        }
        if (arg == "--disk-cache=no") {
            setDiskCacheEnabled(false);
            continue;
        }
        if (arg.startsWith("--max-disk-cache-size=")) {
            setMaxDiskCacheSize(arg.mid(arg.indexOf("=") + 1).trimmed().toInt());
            continue;
        }
        if (arg == "--ignore-ssl-errors=yes") {
            setIgnoreSslErrors(true);
            continue;
        }
        if (arg == "--ignore-ssl-errors=no") {
            setIgnoreSslErrors(false);
            continue;
        }
        if (arg == "--local-to-remote-url-access=no") {
            setLocalToRemoteUrlAccessEnabled(false);
            continue;
        }
        if (arg == "--local-to-remote-url-access=yes") {
            setLocalToRemoteUrlAccessEnabled(true);
            continue;
        }
        if (arg.startsWith("--proxy-type=")) {
            setProxyType(arg.mid(13).trimmed());
            continue;
        }
        if (arg.startsWith("--proxy=")) {
            setProxy(arg.mid(8).trimmed());
            continue;
        }
        if (arg.startsWith("--cookies-file=")) {
            setCookiesFile(arg.mid(15).trimmed());
            continue;
        }
        if (arg.startsWith("--output-encoding=")) {
            setOutputEncoding(arg.mid(18).trimmed());
            continue;
        }
        if (arg.startsWith("--script-encoding=")) {
            setScriptEncoding(arg.mid(18).trimmed());
            continue;
        }
        if (arg.startsWith("--config=")) {
            QString configPath = arg.mid(9).trimmed();
            loadJsonFile(configPath);
            continue;
        }
        if (arg.startsWith("--remote-debugger-port=")) {
            setDebug(true);
            setRemoteDebugPort(arg.mid(23).trimmed().toInt());
            continue;
        }
        if (arg.startsWith("--")) {
            setUnknownOption(QString("Unknown option '%1'").arg(arg));
            return;
        }

        // There are no more options at this point.
        // The remaining arguments are available for the script.

        m_scriptFile = arg;

        while (it.hasNext()) {
            m_scriptArgs += it.next();
        }
    }
}

static QString normalizePath(const QString &path)
{
    return path.isEmpty() ? path : QDir::fromNativeSeparators(path);
}

void Config::loadJsonFile(const QString &filePath)
{
    QString jsonConfig;
    QFile f(filePath);

    // Check file exists and is readable
    if (!f.exists() || !f.open(QFile::ReadOnly | QFile::Text)) {
        Terminal::instance()->cerr("Unable to open config: \"" + filePath + "\"");
        return;
    }

    // Read content
    jsonConfig = QString::fromUtf8(f.readAll().trimmed());
    f.close();

    // Check it's a valid JSON format
    if (jsonConfig.isEmpty() || !jsonConfig.startsWith('{') || !jsonConfig.endsWith('}')) {
        Terminal::instance()->cerr("Config file MUST be in JSON format!");
        return;
    }

    // Load configurator
    QString configurator = Utils::readResourceFileUtf8(":/configurator.js");

    // Use a temporary QWebPage to load the JSON configuration in this Object using the 'configurator' above
    QWebPage webPage;
    // Add this object to the global scope
    webPage.mainFrame()->addToJavaScriptWindowObject("config", this);
    // Apply the JSON config settings to this very object
    webPage.mainFrame()->evaluateJavaScript(configurator.arg(jsonConfig));
}

bool Config::autoLoadImages() const
{
    return m_autoLoadImages;
}

void Config::setAutoLoadImages(const bool value)
{
    m_autoLoadImages = value;
}

QString Config::cookiesFile() const
{
    return m_cookiesFile;
}

void Config::setCookiesFile(const QString &value)
{
    m_cookiesFile = value;
}

bool Config::diskCacheEnabled() const
{
    return m_diskCacheEnabled;
}

void Config::setDiskCacheEnabled(const bool value)
{
    m_diskCacheEnabled = value;
}

int Config::maxDiskCacheSize() const
{
    return m_maxDiskCacheSize;
}

void Config::setMaxDiskCacheSize(int maxDiskCacheSize)
{
    m_maxDiskCacheSize = maxDiskCacheSize;
}

bool Config::ignoreSslErrors() const
{
    return m_ignoreSslErrors;
}

void Config::setIgnoreSslErrors(const bool value)
{
    m_ignoreSslErrors = value;
}

bool Config::localToRemoteUrlAccessEnabled() const
{
    return m_localToRemoteUrlAccessEnabled;
}

void Config::setLocalToRemoteUrlAccessEnabled(const bool value)
{
    m_localToRemoteUrlAccessEnabled = value;
}

QString Config::outputEncoding() const
{
    return m_outputEncoding;
}

void Config::setOutputEncoding(const QString &value)
{
    if (value.isEmpty()) {
        return;
    }

    m_outputEncoding = value;
}

bool Config::pluginsEnabled() const
{
    return m_pluginsEnabled;
}

void Config::setPluginsEnabled(const bool value)
{
    m_pluginsEnabled = value;
}

QString Config::proxyType() const
{
    return m_proxyType;
}

void Config::setProxyType(const QString value)
{
    m_proxyType = value;
}

QString Config::proxy() const
{
    return proxyHost() + ":" + proxyPort();
}

void Config::setProxy(const QString &value)
{
    QString proxyHost = value;
    int proxyPort = 1080;

    if (proxyHost.lastIndexOf(':') > 0) {
        bool ok = true;
        int port = proxyHost.mid(proxyHost.lastIndexOf(':') + 1).toInt(&ok);
        if (ok) {
            proxyHost = proxyHost.left(proxyHost.lastIndexOf(':')).trimmed();
            proxyPort = port;
        }
    }

    setProxyHost(proxyHost);
    setProxyPort(proxyPort);
}

QString Config::proxyHost() const
{
    return m_proxyHost;
}

int Config::proxyPort() const
{
    return m_proxyPort;
}

QStringList Config::scriptArgs() const
{
    return m_scriptArgs;
}

void Config::setScriptArgs(const QStringList &value)
{
    m_scriptArgs.clear();

    QStringListIterator it(value);
    while (it.hasNext()) {
        m_scriptArgs.append(it.next());
    }
}

QString Config::scriptEncoding() const
{
    return m_scriptEncoding;
}

void Config::setScriptEncoding(const QString &value)
{
    if (value.isEmpty()) {
        return;
    }

    m_scriptEncoding = value;
}

QString Config::scriptFile() const
{
    return m_scriptFile;
}

void Config::setScriptFile(const QString &value)
{
    m_scriptFile = value;
}

QString Config::unknownOption() const
{
    return m_unknownOption;
}

void Config::setUnknownOption(const QString &value)
{
    m_unknownOption = value;
}

bool Config::versionFlag() const
{
    return m_versionFlag;
}

void Config::setVersionFlag(const bool value)
{
    m_versionFlag = value;
}

bool Config::debug() const
{
    return m_debug;
}

void Config::setDebug(const bool value)
{
    m_debug = value;
}

int Config::remoteDebugPort() const
{
    return m_remoteDebugPort;
}

void Config::setRemoteDebugPort(const int port)
{
    m_remoteDebugPort = port;
}

// private:
void Config::resetToDefaults()
{
    m_autoLoadImages = true;
    m_cookiesFile = QString();
    m_diskCacheEnabled = false;
    m_maxDiskCacheSize = -1;
    m_ignoreSslErrors = false;
    m_localToRemoteUrlAccessEnabled = false;
    m_outputEncoding = "UTF-8";
    m_pluginsEnabled = false;
    m_proxyType = "http";
    m_proxyHost.clear();
    m_proxyPort = 1080;
    m_scriptArgs.clear();
    m_scriptEncoding = "UTF-8";
    m_scriptFile.clear();
    m_unknownOption.clear();
    m_versionFlag = false;
    m_debug = false;
    m_remoteDebugPort = -1;
}

void Config::setProxyHost(const QString &value)
{
    m_proxyHost = value;
}

void Config::setProxyPort(const int value)
{
    m_proxyPort = value;
}
<commit_msg>Removing a 1 liner method (aka, almost useless) that indeed is not declared (hence, unusable).<commit_after>/*
  This file is part of the PhantomJS project from Ofi Labs.

  Copyright (C) 2011 Ariya Hidayat <ariya.hidayat@gmail.com>
  Copyright (C) 2011 execjosh, http://execjosh.blogspot.com

  Redistribution and use in source and binary forms, with or without
  modification, are permitted provided that the following conditions are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of the <organization> nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include "config.h"

#include <QDir>
#include <QWebPage>
#include <QWebFrame>
#include <QNetworkProxy>

#include "terminal.h"
#include "utils.h"

// public:
Config::Config(QObject *parent)
    : QObject(parent)
{
    resetToDefaults();
}

void Config::init(const QStringList *const args)
{
    resetToDefaults();

    processArgs(*args);
}

void Config::processArgs(const QStringList &args)
{
    QStringListIterator it(args);
    while (it.hasNext()) {
        const QString &arg = it.next();

        if (arg == "--version") {
            setVersionFlag(true);
            return;
        }
        if (arg == "--load-images=yes") {
            setAutoLoadImages(true);
            continue;
        }
        if (arg == "--load-images=no") {
            setAutoLoadImages(false);
            continue;
        }
        if (arg == "--load-plugins=yes") {
            setPluginsEnabled(true);
            continue;
        }
        if (arg == "--load-plugins=no") {
            setPluginsEnabled(false);
            continue;
        }
        if (arg == "--disk-cache=yes") {
            setDiskCacheEnabled(true);
            continue;
        }
        if (arg == "--disk-cache=no") {
            setDiskCacheEnabled(false);
            continue;
        }
        if (arg.startsWith("--max-disk-cache-size=")) {
            setMaxDiskCacheSize(arg.mid(arg.indexOf("=") + 1).trimmed().toInt());
            continue;
        }
        if (arg == "--ignore-ssl-errors=yes") {
            setIgnoreSslErrors(true);
            continue;
        }
        if (arg == "--ignore-ssl-errors=no") {
            setIgnoreSslErrors(false);
            continue;
        }
        if (arg == "--local-to-remote-url-access=no") {
            setLocalToRemoteUrlAccessEnabled(false);
            continue;
        }
        if (arg == "--local-to-remote-url-access=yes") {
            setLocalToRemoteUrlAccessEnabled(true);
            continue;
        }
        if (arg.startsWith("--proxy-type=")) {
            setProxyType(arg.mid(13).trimmed());
            continue;
        }
        if (arg.startsWith("--proxy=")) {
            setProxy(arg.mid(8).trimmed());
            continue;
        }
        if (arg.startsWith("--cookies-file=")) {
            setCookiesFile(arg.mid(15).trimmed());
            continue;
        }
        if (arg.startsWith("--output-encoding=")) {
            setOutputEncoding(arg.mid(18).trimmed());
            continue;
        }
        if (arg.startsWith("--script-encoding=")) {
            setScriptEncoding(arg.mid(18).trimmed());
            continue;
        }
        if (arg.startsWith("--config=")) {
            QString configPath = arg.mid(9).trimmed();
            loadJsonFile(configPath);
            continue;
        }
        if (arg.startsWith("--remote-debugger-port=")) {
            setDebug(true);
            setRemoteDebugPort(arg.mid(23).trimmed().toInt());
            continue;
        }
        if (arg.startsWith("--")) {
            setUnknownOption(QString("Unknown option '%1'").arg(arg));
            return;
        }

        // There are no more options at this point.
        // The remaining arguments are available for the script.

        m_scriptFile = arg;

        while (it.hasNext()) {
            m_scriptArgs += it.next();
        }
    }
}

void Config::loadJsonFile(const QString &filePath)
{
    QString jsonConfig;
    QFile f(filePath);

    // Check file exists and is readable
    if (!f.exists() || !f.open(QFile::ReadOnly | QFile::Text)) {
        Terminal::instance()->cerr("Unable to open config: \"" + filePath + "\"");
        return;
    }

    // Read content
    jsonConfig = QString::fromUtf8(f.readAll().trimmed());
    f.close();

    // Check it's a valid JSON format
    if (jsonConfig.isEmpty() || !jsonConfig.startsWith('{') || !jsonConfig.endsWith('}')) {
        Terminal::instance()->cerr("Config file MUST be in JSON format!");
        return;
    }

    // Load configurator
    QString configurator = Utils::readResourceFileUtf8(":/configurator.js");

    // Use a temporary QWebPage to load the JSON configuration in this Object using the 'configurator' above
    QWebPage webPage;
    // Add this object to the global scope
    webPage.mainFrame()->addToJavaScriptWindowObject("config", this);
    // Apply the JSON config settings to this very object
    webPage.mainFrame()->evaluateJavaScript(configurator.arg(jsonConfig));
}

bool Config::autoLoadImages() const
{
    return m_autoLoadImages;
}

void Config::setAutoLoadImages(const bool value)
{
    m_autoLoadImages = value;
}

QString Config::cookiesFile() const
{
    return m_cookiesFile;
}

void Config::setCookiesFile(const QString &value)
{
    m_cookiesFile = value;
}

bool Config::diskCacheEnabled() const
{
    return m_diskCacheEnabled;
}

void Config::setDiskCacheEnabled(const bool value)
{
    m_diskCacheEnabled = value;
}

int Config::maxDiskCacheSize() const
{
    return m_maxDiskCacheSize;
}

void Config::setMaxDiskCacheSize(int maxDiskCacheSize)
{
    m_maxDiskCacheSize = maxDiskCacheSize;
}

bool Config::ignoreSslErrors() const
{
    return m_ignoreSslErrors;
}

void Config::setIgnoreSslErrors(const bool value)
{
    m_ignoreSslErrors = value;
}

bool Config::localToRemoteUrlAccessEnabled() const
{
    return m_localToRemoteUrlAccessEnabled;
}

void Config::setLocalToRemoteUrlAccessEnabled(const bool value)
{
    m_localToRemoteUrlAccessEnabled = value;
}

QString Config::outputEncoding() const
{
    return m_outputEncoding;
}

void Config::setOutputEncoding(const QString &value)
{
    if (value.isEmpty()) {
        return;
    }

    m_outputEncoding = value;
}

bool Config::pluginsEnabled() const
{
    return m_pluginsEnabled;
}

void Config::setPluginsEnabled(const bool value)
{
    m_pluginsEnabled = value;
}

QString Config::proxyType() const
{
    return m_proxyType;
}

void Config::setProxyType(const QString value)
{
    m_proxyType = value;
}

QString Config::proxy() const
{
    return proxyHost() + ":" + proxyPort();
}

void Config::setProxy(const QString &value)
{
    QString proxyHost = value;
    int proxyPort = 1080;

    if (proxyHost.lastIndexOf(':') > 0) {
        bool ok = true;
        int port = proxyHost.mid(proxyHost.lastIndexOf(':') + 1).toInt(&ok);
        if (ok) {
            proxyHost = proxyHost.left(proxyHost.lastIndexOf(':')).trimmed();
            proxyPort = port;
        }
    }

    setProxyHost(proxyHost);
    setProxyPort(proxyPort);
}

QString Config::proxyHost() const
{
    return m_proxyHost;
}

int Config::proxyPort() const
{
    return m_proxyPort;
}

QStringList Config::scriptArgs() const
{
    return m_scriptArgs;
}

void Config::setScriptArgs(const QStringList &value)
{
    m_scriptArgs.clear();

    QStringListIterator it(value);
    while (it.hasNext()) {
        m_scriptArgs.append(it.next());
    }
}

QString Config::scriptEncoding() const
{
    return m_scriptEncoding;
}

void Config::setScriptEncoding(const QString &value)
{
    if (value.isEmpty()) {
        return;
    }

    m_scriptEncoding = value;
}

QString Config::scriptFile() const
{
    return m_scriptFile;
}

void Config::setScriptFile(const QString &value)
{
    m_scriptFile = value;
}

QString Config::unknownOption() const
{
    return m_unknownOption;
}

void Config::setUnknownOption(const QString &value)
{
    m_unknownOption = value;
}

bool Config::versionFlag() const
{
    return m_versionFlag;
}

void Config::setVersionFlag(const bool value)
{
    m_versionFlag = value;
}

bool Config::debug() const
{
    return m_debug;
}

void Config::setDebug(const bool value)
{
    m_debug = value;
}

int Config::remoteDebugPort() const
{
    return m_remoteDebugPort;
}

void Config::setRemoteDebugPort(const int port)
{
    m_remoteDebugPort = port;
}

// private:
void Config::resetToDefaults()
{
    m_autoLoadImages = true;
    m_cookiesFile = QString();
    m_diskCacheEnabled = false;
    m_maxDiskCacheSize = -1;
    m_ignoreSslErrors = false;
    m_localToRemoteUrlAccessEnabled = false;
    m_outputEncoding = "UTF-8";
    m_pluginsEnabled = false;
    m_proxyType = "http";
    m_proxyHost.clear();
    m_proxyPort = 1080;
    m_scriptArgs.clear();
    m_scriptEncoding = "UTF-8";
    m_scriptFile.clear();
    m_unknownOption.clear();
    m_versionFlag = false;
    m_debug = false;
    m_remoteDebugPort = -1;
}

void Config::setProxyHost(const QString &value)
{
    m_proxyHost = value;
}

void Config::setProxyPort(const int value)
{
    m_proxyPort = value;
}
<|endoftext|>


<commit_before>#include "config.h"

Config* Config::getHandle() {
	static Config instance;
	return &instance;
}

void Config::setMainConfigFile(const std::string& configFileName) {
	if (confname.empty())
		confname = configFileName;
}

void Config::readConfig() {
	config = readConfig(confname, std::ifstream(confname));
	for (auto callback : notifyList)
		callback();
}

enum ConfigState { CONFIG_BLOCK, CONFIG_KEY, CONFIG_VALUE, CONFIG_VALUE_NEXT, CONFIG_VALUE_VAR, CONFIG_VALUE_STR, CONFIG_VALUE_STR_ESCAPED };
// This enum is simply an implementation detail for the configuration parser; hence it is placed here instead of the header file.

std::unordered_multimap<std::string, std::unordered_map<std::string, std::string>> Config::readConfig(const std::string& filename, std::istream&& configData) {
	ConfigState state = CONFIG_BLOCK;
	unsigned int lineNum = 1;
	LogManager* logger = LogManager::getHandle();
	std::string blockName, key, value, valueVar;
	std::unordered_map<std::string, std::string> blockValues;
	std::unordered_multimap<std::string, std::unordered_map<std::string, std::string>> localConfig;
	while (configData.good()) {
		char nextChar = configData.get();
		if (nextChar == std::istream::traits_type::eof())
			break;
		if (nextChar == '\n')
			lineNum++;
		if (state == CONFIG_BLOCK) {
			if (nextChar == '{') {
				if (blockName.empty())
					throw ConfigError (filename, lineNum, "A block without a name was opened.");
				state = CONFIG_KEY;
			} else if (nextChar == '}')
				throw ConfigError (filename, lineNum, "A closing brace could not be mached to an open block.");
			else if (nextChar == '#') {
				while (configData.good() && configData.get() != '\n') {}
				lineNum++;
			} else if (nextChar != ' ' && nextChar != '\t' && nextChar != '\r' && nextChar != '\n')
				blockName += nextChar;
		} else if (state == CONFIG_KEY) {
			if (nextChar == '#') {
				while (configData.good() && configData.get() != '\n') {}
				lineNum++;
			} else if (nextChar == '{')
				throw ConfigError (filename, lineNum, "A block was opened inside another block.");
			else if (nextChar == '}') {
				if (blockValues.empty())
					throw ConfigError (filename, lineNum, "An empty block was defined.  What was the point of that?");
				if (!key.empty() || !value.empty())
					throw ConfigError (filename, lineNum, "A key-value pair was unfinished when the block was terminated.");
				localConfig.insert(std::pair<std::string, std::unordered_map<std::string, std::string>> (blockName, blockValues));
				blockName.clear();
				blockValues.clear();
				logger->log(LOG_ALL, "config", "Block " + blockName + " read.");
				state = CONFIG_BLOCK;
			} else if (nextChar == ';')
				throw ConfigError (filename, lineNum, "A key was specified without a value.");
			else if (nextChar == '=')
				state = CONFIG_VALUE_NEXT;
			else if (nextChar != ' ' && nextChar != '\t' && nextChar != '\r' && nextChar != '\n')
				key += nextChar;
		} else if (state == CONFIG_VALUE) {
			if (nextChar == '#') {
				while (configData.good() && configData.get() != '\n') {}
				lineNum++;
			} else if (nextChar == ';') {
				blockValues.insert(std::pair<std::string, std::string> (key, value));
				key.clear();
				value.clear();
				state = CONFIG_KEY;
			} else if (nextChar == '+')
				state = CONFIG_VALUE_NEXT;
			else
				throw ConfigError (filename, lineNum, "An unexpected character was encountered; expected ';' or '+' (perhaps you forgot to end or properly concatenate your value?).");
		} else if (state == CONFIG_VALUE_NEXT) {
			if (nextChar == '#') {
				while (configData.good() && configData.get() != '\n') {}
				lineNum++;
			} else if (nextChar == '"')
				state = CONFIG_VALUE_STR;
			else if (nextChar != ' ' && nextChar != '\t' && nextChar != '\r' && nextChar != '\n') {
				valueVar += nextChar;
				state = CONFIG_VALUE_VAR;
			}
		} else if (state == CONFIG_VALUE_VAR) {
			if (nextChar == '"')
				throw ConfigError (filename, lineNum, "A string value was specified in the middle of a variable (perhaps you forgot to properly concatenate with '+'?).");
			else if (nextChar == '{')
				throw ConfigError (filename, lineNum, "A block was opened inside another block.");
			else if (nextChar == '}')
				throw ConfigError (filename, lineNum, "A key-value pair was unfinished when the block was terminated.");
			else if (nextChar == ' ' || nextChar == '\t' || nextChar == '\r' || nextChar == '\n' || nextChar == '+' || nextChar == ';') {
				auto keyIter = blockValues.find(valueVar);
				if (keyIter == blockValues.end())
					throw ConfigError (filename, lineNum, "The variable " + valueVar + " was specified, but did not match a variable already specified in the block.");
				value += keyIter->second;
				valueVar.clear();
				if (nextChar == ';') {
					state = CONFIG_KEY;
					blockValues.insert(std::pair<std::string, std::string> (key, value));
					key.clear();
					value.clear();
				} else if (nextChar == '+')
					state = CONFIG_VALUE_NEXT;
				else
					state = CONFIG_VALUE;
			} else
				valueVar += nextChar;
		} else if (state == CONFIG_VALUE_STR) {
			if (nextChar == '\\')
				state = CONFIG_VALUE_STR_ESCAPED;
			else if (nextChar == '"')
				state = CONFIG_VALUE;
			else
				value += nextChar;
		} else if (state == CONFIG_VALUE_STR_ESCAPED) {
			if (nextChar == '\\')
				value += '\\';
			else if (nextChar == 'n')
				value += '\n';
			else if (nextChar == 't')
				value += '\t';
			else if (nextChar == 'r')
				value += '\r';
			else
				value += nextChar;
			state = CONFIG_VALUE_STR;
		}
	}
	if (!blockValues.empty())
		throw ConfigError (filename, lineNum, "A block remained unterminated at the end of the file.");
	std::list<std::unordered_multimap<std::string, std::unordered_map<std::string, std::string>>> includedConfigs;
	for (auto block : localConfig) {
		if (block.first == "include") {
			auto inclfIter = block.second.find("file");
			if (inclfIter != block.second.end()) {
				std::string name = inclfIter->second;
				logger->log(LOG_ALL, "config", "Reading included file " + inclfIter->second);
				includedConfigs.push_back(readConfig(inclfIter->second, std::ifstream(name)));
			} else {
				auto incleIter = block.second.find("executable");
				if (incleIter != block.second.end()) {
					std::string cmd = incleIter->second;
					logger->log(LOG_ALL, "config", "Getting configuration data from `" + incleIter->second + "`");
					FILE* pipe = popen(cmd.c_str(), "r");
					if (!pipe)
						throw ConfigError (cmd, 0, "Could not open pipe to read output.");
					char buffer[256];
					std::stringstream output;
					while (!feof(pipe)) {
						if (fgets(buffer, 256, pipe) != NULL)
							output << buffer;
					}
					pclose(pipe);
					includedConfigs.push_back(readConfig(cmd, output));
				} else
					throw ConfigError (filename, lineNum, "An include block was present that contained neither a file nor an executable.");
			}
		}
	}
	for (auto includes : includedConfigs) {
		for (auto conf : includes) {
			for (auto block : conf)
				localConfig.insert(std::pair<std::string, std::unordered_map<std::string, std::string>> (block.first, block.second));
		}
	}
	return localConfig;
}

void Config::addRehashNotify(std::function<void()> notifyCallback) {
	notifyList.push_back(notifyCallback);
}

size_t Config::blockCount(const std::string& block) const {
	return config.count(block);
}

std::list<std::unordered_map<std::string, std::string>> Config::getBlock(const std::string& block) const {
	std::list<std::unordered_map<std::string, std::string>> blockList;
	std::unordered_multimap<std::string, std::unordered_map<std::string, std::string>>::const_iterator startIter, endIter;
	std::tie(startIter, endIter) = config.equal_range(block);
	for (; startIter != endIter; ++startIter)
		blockList.push_back(startIter->second);
	return blockList;
}

std::unordered_map<std::string, std::string> Config::getSingleBlock(const std::string& block, const std::unordered_map<std::string, std::string>& conditions) const {
	std::unordered_multimap<std::string, std::unordered_map<std::string, std::string>>::const_iterator startIter, endIter;
	std::tie(startIter, endIter) = config.equal_range(block);
	for (; startIter != endIter; ++startIter) {
		for (auto check : conditions) {
			auto blockIter = startIter->second.find(check.first);
			if (blockIter == startIter->second.end())
				continue;
			if (check.second == blockIter->second)
				return startIter->second;
		}
	}
	return std::unordered_map<std::string, std::string> ();
}

std::string Config::getValue(const std::string& block, const std::string& key) const {
	auto blockIter = config.find(block);
	if (blockIter == config.end())
		return "";
	auto dataIter = blockIter->second.find(key);
	if (dataIter == blockIter->second.end())
		return "";
	return dataIter->second;
}

bool Config::getBoolValue(const std::string& block, const std::string& key) const {
	const std::string& value = getValue(block, key);
	std::string lowerValue;
	std::transform(value.begin(), value.end(), std::back_inserter(lowerValue), ::tolower);
	if (lowerValue == "yes" || lowerValue == "on" || lowerValue == "true")
		return true;
	return false;
}

std::list<std::string> Config::getAllValues(const std::string& block, const std::string& key) const {
	std::list<std::string> valueList;
	std::unordered_multimap<std::string, std::unordered_map<std::string, std::string>>::const_iterator startIter, endIter;
	std::tie(startIter, endIter) = config.equal_range(block);
	for (; startIter != endIter; ++startIter) {
		auto dataIter = startIter->second.find(key);
		if (dataIter == startIter->second.end())
			valueList.push_back("");
		else
			valueList.push_back(dataIter->second);
	}
	return valueList;
}

std::list<bool> Config::getAllBoolValues(const std::string& block, const std::string& key) const {
	std::list<bool> valueList;
	std::unordered_multimap<std::string, std::unordered_map<std::string, std::string>>::const_iterator startIter, endIter;
	std::tie(startIter, endIter) = config.equal_range(block);
	for (std::string lowerValue; startIter != endIter; ++startIter) {
		auto dataIter = startIter->second.find(key);
		if (dataIter == startIter->second.end())
			valueList.push_back(false);
		else {
			lowerValue.clear();
			std::transform(dataIter->second.begin(), dataIter->second.end(), std::back_inserter(lowerValue), ::tolower);
			if (lowerValue == "yes" || lowerValue == "on" || lowerValue == "true")
				valueList.push_back(true);
			else
				valueList.push_back(false);
		}
	}
	return valueList;
}

bool Config::makeBool(const std::string& value) {
	std::string lowerValue;
	std::transform(value.begin(), value.end(), std::back_inserter(lowerValue), ::tolower);
	if (lowerValue == "yes" || lowerValue == "on" || lowerValue == "true")
		return true;
	return false;
}

Config::Config() {}

ConfigError::ConfigError(const std::string& filename, unsigned int lineNum, const std::string& description) {
	std::ostringstream descStr;
	descStr << "An error occurred reading the configuration from '" << filename << "' on line " << lineNum << ": " << description;
	desc = descStr.str();
}<commit_msg>Properly expand included config for merging with the local one<commit_after>#include "config.h"

Config* Config::getHandle() {
	static Config instance;
	return &instance;
}

void Config::setMainConfigFile(const std::string& configFileName) {
	if (confname.empty())
		confname = configFileName;
}

void Config::readConfig() {
	config = readConfig(confname, std::ifstream(confname));
	for (auto callback : notifyList)
		callback();
}

enum ConfigState { CONFIG_BLOCK, CONFIG_KEY, CONFIG_VALUE, CONFIG_VALUE_NEXT, CONFIG_VALUE_VAR, CONFIG_VALUE_STR, CONFIG_VALUE_STR_ESCAPED };
// This enum is simply an implementation detail for the configuration parser; hence it is placed here instead of the header file.

std::unordered_multimap<std::string, std::unordered_map<std::string, std::string>> Config::readConfig(const std::string& filename, std::istream&& configData) {
	ConfigState state = CONFIG_BLOCK;
	unsigned int lineNum = 1;
	LogManager* logger = LogManager::getHandle();
	std::string blockName, key, value, valueVar;
	std::unordered_map<std::string, std::string> blockValues;
	std::unordered_multimap<std::string, std::unordered_map<std::string, std::string>> localConfig;
	while (configData.good()) {
		char nextChar = configData.get();
		if (nextChar == std::istream::traits_type::eof())
			break;
		if (nextChar == '\n')
			lineNum++;
		if (state == CONFIG_BLOCK) {
			if (nextChar == '{') {
				if (blockName.empty())
					throw ConfigError (filename, lineNum, "A block without a name was opened.");
				state = CONFIG_KEY;
			} else if (nextChar == '}')
				throw ConfigError (filename, lineNum, "A closing brace could not be mached to an open block.");
			else if (nextChar == '#') {
				while (configData.good() && configData.get() != '\n') {}
				lineNum++;
			} else if (nextChar != ' ' && nextChar != '\t' && nextChar != '\r' && nextChar != '\n')
				blockName += nextChar;
		} else if (state == CONFIG_KEY) {
			if (nextChar == '#') {
				while (configData.good() && configData.get() != '\n') {}
				lineNum++;
			} else if (nextChar == '{')
				throw ConfigError (filename, lineNum, "A block was opened inside another block.");
			else if (nextChar == '}') {
				if (blockValues.empty())
					throw ConfigError (filename, lineNum, "An empty block was defined.  What was the point of that?");
				if (!key.empty() || !value.empty())
					throw ConfigError (filename, lineNum, "A key-value pair was unfinished when the block was terminated.");
				localConfig.insert(std::pair<std::string, std::unordered_map<std::string, std::string>> (blockName, blockValues));
				blockName.clear();
				blockValues.clear();
				logger->log(LOG_ALL, "config", "Block " + blockName + " read.");
				state = CONFIG_BLOCK;
			} else if (nextChar == ';')
				throw ConfigError (filename, lineNum, "A key was specified without a value.");
			else if (nextChar == '=')
				state = CONFIG_VALUE_NEXT;
			else if (nextChar != ' ' && nextChar != '\t' && nextChar != '\r' && nextChar != '\n')
				key += nextChar;
		} else if (state == CONFIG_VALUE) {
			if (nextChar == '#') {
				while (configData.good() && configData.get() != '\n') {}
				lineNum++;
			} else if (nextChar == ';') {
				blockValues.insert(std::pair<std::string, std::string> (key, value));
				key.clear();
				value.clear();
				state = CONFIG_KEY;
			} else if (nextChar == '+')
				state = CONFIG_VALUE_NEXT;
			else
				throw ConfigError (filename, lineNum, "An unexpected character was encountered; expected ';' or '+' (perhaps you forgot to end or properly concatenate your value?).");
		} else if (state == CONFIG_VALUE_NEXT) {
			if (nextChar == '#') {
				while (configData.good() && configData.get() != '\n') {}
				lineNum++;
			} else if (nextChar == '"')
				state = CONFIG_VALUE_STR;
			else if (nextChar != ' ' && nextChar != '\t' && nextChar != '\r' && nextChar != '\n') {
				valueVar += nextChar;
				state = CONFIG_VALUE_VAR;
			}
		} else if (state == CONFIG_VALUE_VAR) {
			if (nextChar == '"')
				throw ConfigError (filename, lineNum, "A string value was specified in the middle of a variable (perhaps you forgot to properly concatenate with '+'?).");
			else if (nextChar == '{')
				throw ConfigError (filename, lineNum, "A block was opened inside another block.");
			else if (nextChar == '}')
				throw ConfigError (filename, lineNum, "A key-value pair was unfinished when the block was terminated.");
			else if (nextChar == ' ' || nextChar == '\t' || nextChar == '\r' || nextChar == '\n' || nextChar == '+' || nextChar == ';') {
				auto keyIter = blockValues.find(valueVar);
				if (keyIter == blockValues.end())
					throw ConfigError (filename, lineNum, "The variable " + valueVar + " was specified, but did not match a variable already specified in the block.");
				value += keyIter->second;
				valueVar.clear();
				if (nextChar == ';') {
					state = CONFIG_KEY;
					blockValues.insert(std::pair<std::string, std::string> (key, value));
					key.clear();
					value.clear();
				} else if (nextChar == '+')
					state = CONFIG_VALUE_NEXT;
				else
					state = CONFIG_VALUE;
			} else
				valueVar += nextChar;
		} else if (state == CONFIG_VALUE_STR) {
			if (nextChar == '\\')
				state = CONFIG_VALUE_STR_ESCAPED;
			else if (nextChar == '"')
				state = CONFIG_VALUE;
			else
				value += nextChar;
		} else if (state == CONFIG_VALUE_STR_ESCAPED) {
			if (nextChar == '\\')
				value += '\\';
			else if (nextChar == 'n')
				value += '\n';
			else if (nextChar == 't')
				value += '\t';
			else if (nextChar == 'r')
				value += '\r';
			else
				value += nextChar;
			state = CONFIG_VALUE_STR;
		}
	}
	if (!blockValues.empty())
		throw ConfigError (filename, lineNum, "A block remained unterminated at the end of the file.");
	std::list<std::unordered_multimap<std::string, std::unordered_map<std::string, std::string>>> includedConfigs;
	for (auto block : localConfig) {
		if (block.first == "include") {
			auto inclfIter = block.second.find("file");
			if (inclfIter != block.second.end()) {
				std::string name = inclfIter->second;
				logger->log(LOG_ALL, "config", "Reading included file " + inclfIter->second);
				includedConfigs.push_back(readConfig(inclfIter->second, std::ifstream(name)));
			} else {
				auto incleIter = block.second.find("executable");
				if (incleIter != block.second.end()) {
					std::string cmd = incleIter->second;
					logger->log(LOG_ALL, "config", "Getting configuration data from `" + incleIter->second + "`");
					FILE* pipe = popen(cmd.c_str(), "r");
					if (!pipe)
						throw ConfigError (cmd, 0, "Could not open pipe to read output.");
					char buffer[256];
					std::stringstream output;
					while (!feof(pipe)) {
						if (fgets(buffer, 256, pipe) != NULL)
							output << buffer;
					}
					pclose(pipe);
					includedConfigs.push_back(readConfig(cmd, output));
				} else
					throw ConfigError (filename, lineNum, "An include block was present that contained neither a file nor an executable.");
			}
		}
	}
	for (auto includes : includedConfigs) {
		for (auto conf : includes) {
			for (auto block : conf.second)
				localConfig.insert(std::pair<std::string, std::unordered_map<std::string, std::string>> (block.first, block.second));
		}
	}
	return localConfig;
}

void Config::addRehashNotify(std::function<void()> notifyCallback) {
	notifyList.push_back(notifyCallback);
}

size_t Config::blockCount(const std::string& block) const {
	return config.count(block);
}

std::list<std::unordered_map<std::string, std::string>> Config::getBlock(const std::string& block) const {
	std::list<std::unordered_map<std::string, std::string>> blockList;
	std::unordered_multimap<std::string, std::unordered_map<std::string, std::string>>::const_iterator startIter, endIter;
	std::tie(startIter, endIter) = config.equal_range(block);
	for (; startIter != endIter; ++startIter)
		blockList.push_back(startIter->second);
	return blockList;
}

std::unordered_map<std::string, std::string> Config::getSingleBlock(const std::string& block, const std::unordered_map<std::string, std::string>& conditions) const {
	std::unordered_multimap<std::string, std::unordered_map<std::string, std::string>>::const_iterator startIter, endIter;
	std::tie(startIter, endIter) = config.equal_range(block);
	for (; startIter != endIter; ++startIter) {
		for (auto check : conditions) {
			auto blockIter = startIter->second.find(check.first);
			if (blockIter == startIter->second.end())
				continue;
			if (check.second == blockIter->second)
				return startIter->second;
		}
	}
	return std::unordered_map<std::string, std::string> ();
}

std::string Config::getValue(const std::string& block, const std::string& key) const {
	auto blockIter = config.find(block);
	if (blockIter == config.end())
		return "";
	auto dataIter = blockIter->second.find(key);
	if (dataIter == blockIter->second.end())
		return "";
	return dataIter->second;
}

bool Config::getBoolValue(const std::string& block, const std::string& key) const {
	const std::string& value = getValue(block, key);
	std::string lowerValue;
	std::transform(value.begin(), value.end(), std::back_inserter(lowerValue), ::tolower);
	if (lowerValue == "yes" || lowerValue == "on" || lowerValue == "true")
		return true;
	return false;
}

std::list<std::string> Config::getAllValues(const std::string& block, const std::string& key) const {
	std::list<std::string> valueList;
	std::unordered_multimap<std::string, std::unordered_map<std::string, std::string>>::const_iterator startIter, endIter;
	std::tie(startIter, endIter) = config.equal_range(block);
	for (; startIter != endIter; ++startIter) {
		auto dataIter = startIter->second.find(key);
		if (dataIter == startIter->second.end())
			valueList.push_back("");
		else
			valueList.push_back(dataIter->second);
	}
	return valueList;
}

std::list<bool> Config::getAllBoolValues(const std::string& block, const std::string& key) const {
	std::list<bool> valueList;
	std::unordered_multimap<std::string, std::unordered_map<std::string, std::string>>::const_iterator startIter, endIter;
	std::tie(startIter, endIter) = config.equal_range(block);
	for (std::string lowerValue; startIter != endIter; ++startIter) {
		auto dataIter = startIter->second.find(key);
		if (dataIter == startIter->second.end())
			valueList.push_back(false);
		else {
			lowerValue.clear();
			std::transform(dataIter->second.begin(), dataIter->second.end(), std::back_inserter(lowerValue), ::tolower);
			if (lowerValue == "yes" || lowerValue == "on" || lowerValue == "true")
				valueList.push_back(true);
			else
				valueList.push_back(false);
		}
	}
	return valueList;
}

bool Config::makeBool(const std::string& value) {
	std::string lowerValue;
	std::transform(value.begin(), value.end(), std::back_inserter(lowerValue), ::tolower);
	if (lowerValue == "yes" || lowerValue == "on" || lowerValue == "true")
		return true;
	return false;
}

Config::Config() {}

ConfigError::ConfigError(const std::string& filename, unsigned int lineNum, const std::string& description) {
	std::ostringstream descStr;
	descStr << "An error occurred reading the configuration from '" << filename << "' on line " << lineNum << ": " << description;
	desc = descStr.str();
}<|endoftext|>


<commit_before>#include "openmc/source.h"

#include <algorithm> // for move
#include <sstream> // for stringstream

#if defined (__unix__) || (defined (__APPLE__) && defined (__MACH__))
#include <dlfcn.h> // for dlopen
#endif

#include <fmt/core.h>
#include "xtensor/xadapt.hpp"

#include "openmc/bank.h"
#include "openmc/cell.h"
#include "openmc/error.h"
#include "openmc/file_utils.h"
#include "openmc/hdf5_interface.h"
#include "openmc/material.h"
#include "openmc/message_passing.h"
#include "openmc/mgxs_interface.h"
#include "openmc/nuclide.h"
#include "openmc/capi.h"
#include "openmc/random_lcg.h"
#include "openmc/search.h"
#include "openmc/settings.h"
#include "openmc/simulation.h"
#include "openmc/state_point.h"
#include "openmc/xml_interface.h"

namespace openmc {

//==============================================================================
// Global variables
//==============================================================================

namespace model {

std::vector<SourceDistribution> external_sources;

}

//==============================================================================
// SourceDistribution implementation
//==============================================================================

SourceDistribution::SourceDistribution(UPtrSpace space, UPtrAngle angle, UPtrDist energy)
  : space_{std::move(space)}, angle_{std::move(angle)}, energy_{std::move(energy)} { }

SourceDistribution::SourceDistribution(pugi::xml_node node)
{
  // Check for particle type
  if (check_for_node(node, "particle")) {
    auto temp_str = get_node_value(node, "particle", true, true);
    if (temp_str == "neutron") {
      particle_ = Particle::Type::neutron;
    } else if (temp_str == "photon") {
      particle_ = Particle::Type::photon;
      settings::photon_transport = true;
    } else {
      fatal_error(std::string("Unknown source particle type: ") + temp_str);
    }
  }

  // Check for source strength
  if (check_for_node(node, "strength")) {
    strength_ = std::stod(get_node_value(node, "strength"));
  }

  // Check for external source file
  if (check_for_node(node, "file")) {
    // Copy path of source file
    settings::path_source = get_node_value(node, "file", false, true);

    // Check if source file exists
    if (!file_exists(settings::path_source)) {
      fatal_error(fmt::format("Source file '{}' does not exist.",
        settings::path_source));
    }
  } else if (check_for_node(node, "library")) {
     settings::path_source_library = get_node_value(node, "library", false, true);
     // check if it exists
     if (!file_exists(settings::path_source_library)) {
      	std::stringstream msg;
      	msg << "Library file " << settings::path_source_library << "' does not exist.";
	      fatal_error(msg);
     }
  } else {

    // Spatial distribution for external source
    if (check_for_node(node, "space")) {
      // Get pointer to spatial distribution
      pugi::xml_node node_space = node.child("space");

      // Check for type of spatial distribution and read
      std::string type;
      if (check_for_node(node_space, "type"))
        type = get_node_value(node_space, "type", true, true);
      if (type == "cartesian") {
        space_ = UPtrSpace{new CartesianIndependent(node_space)};
      } else if (type == "cylindrical") {
        space_ = UPtrSpace{new CylindricalIndependent(node_space)};
      } else if (type == "spherical") {
        space_ = UPtrSpace{new SphericalIndependent(node_space)};
      } else if (type == "box") {
        space_ = UPtrSpace{new SpatialBox(node_space)};
      } else if (type == "fission") {
        space_ = UPtrSpace{new SpatialBox(node_space, true)};
      } else if (type == "point") {
        space_ = UPtrSpace{new SpatialPoint(node_space)};
      } else {
        fatal_error(fmt::format(
          "Invalid spatial distribution for external source: {}", type));
      }

    } else {
      // If no spatial distribution specified, make it a point source
      space_ = UPtrSpace{new SpatialPoint()};
    }

    // Determine external source angular distribution
    if (check_for_node(node, "angle")) {
      // Get pointer to angular distribution
      pugi::xml_node node_angle = node.child("angle");

      // Check for type of angular distribution
      std::string type;
      if (check_for_node(node_angle, "type"))
        type = get_node_value(node_angle, "type", true, true);
      if (type == "isotropic") {
        angle_ = UPtrAngle{new Isotropic()};
      } else if (type == "monodirectional") {
        angle_ = UPtrAngle{new Monodirectional(node_angle)};
      } else if (type == "mu-phi") {
        angle_ = UPtrAngle{new PolarAzimuthal(node_angle)};
      } else {
        fatal_error(fmt::format(
          "Invalid angular distribution for external source: {}", type));
      }

    } else {
      angle_ = UPtrAngle{new Isotropic()};
    }

    // Determine external source energy distribution
    if (check_for_node(node, "energy")) {
      pugi::xml_node node_dist = node.child("energy");
      energy_ = distribution_from_xml(node_dist);
    } else {
      // Default to a Watt spectrum with parameters 0.988 MeV and 2.249 MeV^-1
      energy_ = UPtrDist{new Watt(0.988e6, 2.249e-6)};
    }
  }
}

Particle::Bank SourceDistribution::sample(uint64_t* seed) const
{
  Particle::Bank site;

  // Set weight to one by default
  site.wgt = 1.0;

  // Repeat sampling source location until a good site has been found
  bool found = false;
  int n_reject = 0;
  static int n_accept = 0;
  while (!found) {
    // Set particle type
    site.particle = particle_;

    // Sample spatial distribution
    site.r = space_->sample(seed);
    double xyz[] {site.r.x, site.r.y, site.r.z};

    // Now search to see if location exists in geometry
    int32_t cell_index, instance;
    int err = openmc_find_cell(xyz, &cell_index, &instance);
    found = (err != OPENMC_E_GEOMETRY);

    // Check if spatial site is in fissionable material
    if (found) {
      auto space_box = dynamic_cast<SpatialBox*>(space_.get());
      if (space_box) {
        if (space_box->only_fissionable()) {
          // Determine material
          const auto& c = model::cells[cell_index];
          auto mat_index = c->material_.size() == 1
            ? c->material_[0] : c->material_[instance];

          if (mat_index == MATERIAL_VOID) {
            found = false;
          } else {
            if (!model::materials[mat_index]->fissionable_) found = false;
          }
        }
      }
    }

    // Check for rejection
    if (!found) {
      ++n_reject;
      if (n_reject >= EXTSRC_REJECT_THRESHOLD &&
          static_cast<double>(n_accept)/n_reject <= EXTSRC_REJECT_FRACTION) {
        fatal_error("More than 95% of external source sites sampled were "
                    "rejected. Please check your external source definition.");
      }
    }
  }

  // Increment number of accepted samples
  ++n_accept;

  // Sample angle
  site.u = angle_->sample(seed);

  // Check for monoenergetic source above maximum particle energy
  auto p = static_cast<int>(particle_);
  auto energy_ptr = dynamic_cast<Discrete*>(energy_.get());
  if (energy_ptr) {
    auto energies = xt::adapt(energy_ptr->x());
    if (xt::any(energies > data::energy_max[p])) {
      fatal_error("Source energy above range of energies of at least "
                  "one cross section table");
    } else if (xt::any(energies < data::energy_min[p])) {
      fatal_error("Source energy below range of energies of at least "
                  "one cross section table");
    }
  }

  while (true) {
    // Sample energy spectrum
    site.E = energy_->sample(seed);

    // Resample if energy falls outside minimum or maximum particle energy
    if (site.E < data::energy_max[p] && site.E > data::energy_min[p]) break;
  }

  // Set delayed group
  site.delayed_group = 0;

  return site;
}

//==============================================================================
// Non-member functions
//==============================================================================

void initialize_source()
{
  write_message("Initializing source particles...", 5);

  if (settings::path_source != "") {
    // Read the source from a binary file instead of sampling from some
    // assumed source distribution

    write_message(fmt::format("Reading source file from {}...",
      settings::path_source), 6);

    // Open the binary file
    hid_t file_id = file_open(settings::path_source, 'r', true);

    // Read the file type
    std::string filetype;
    read_attribute(file_id, "filetype", filetype);

    // Check to make sure this is a source file
    if (filetype != "source" && filetype != "statepoint") {
      fatal_error("Specified starting source file not a source file type.");
    }

    // Read in the source bank
    read_source_bank(file_id);

    // Close file
    file_close(file_id);
  } else if ( settings::path_source_library != "" ) {
    // Get the source from a library object

    std::stringstream msg;
    msg << "Sampling from library source " << settings::path_source << "...";
    write_message(msg, 6);

    #if defined (__unix__) || (defined (__APPLE__) && defined (__MACH__))
    // Open the library
    void* source_library = dlopen(settings::path_source_library.c_str(),RTLD_LAZY);
    if(!source_library) {
      std::stringstream msg("Couldn't open source library " + settings::path_source_library);
      fatal_error(msg);
    }
    #else
    std::stringstream msg("This feature has not yet been implemented for non POSIX systems");
    fatal_error(msg);
    #endif

    // load the symbol
    typedef Particle::Bank (*sample_t)(uint64_t seed);

    // reset errors
    dlerror();

    // get the function from the library
    sample_t sample_source = (sample_t) dlsym(source_library, "sample_source");
    const char *dlsym_error = dlerror();

    // check for any dlsym errors
    if (dlsym_error) {
      std::cout << dlsym_error << std::endl;
      dlclose(source_library);
      fatal_error("Couldn't open the sample_source symbol");
    }

    // Generation source sites from specified distribution in the
    // library source
    for (int64_t i = 0; i < simulation::work_per_rank; ++i) {
      // initialize random number seed
      int64_t id = simulation::total_gen*settings::n_particles +
        simulation::work_index[mpi::rank] + i + 1;
      uint64_t seed = init_seed(id, STREAM_SOURCE);

      // sample external source distribution
      simulation::source_bank[i] = sample_source(seed);
    }
    // release the library
    dlclose(source_library);

  } else {
    // Generation source sites from specified distribution in user input
    for (int64_t i = 0; i < simulation::work_per_rank; ++i) {
      // initialize random number seed
      int64_t id = simulation::total_gen*settings::n_particles +
        simulation::work_index[mpi::rank] + i + 1;
      uint64_t seed = init_seed(id, STREAM_SOURCE);

      // sample external source distribution
      simulation::source_bank[i] = sample_external_source(&seed);
    }
  }

  // Write out initial source
  if (settings::write_initial_source) {
    write_message("Writing out initial source...", 5);
    std::string filename = settings::path_output + "initial_source.h5";
    hid_t file_id = file_open(filename, 'w', true);
    write_source_bank(file_id);
    file_close(file_id);
  }
}

Particle::Bank sample_external_source(uint64_t* seed)
{
  // Determine total source strength
  double total_strength = 0.0;
  for (auto& s : model::external_sources)
    total_strength += s.strength();

  // Sample from among multiple source distributions
  int i = 0;
  if (model::external_sources.size() > 1) {
    double xi = prn(seed)*total_strength;
    double c = 0.0;
    for (; i < model::external_sources.size(); ++i) {
      c += model::external_sources[i].strength();
      if (xi < c) break;
    }
  }

  // Sample source site from i-th source distribution
  Particle::Bank site {model::external_sources[i].sample(seed)};

  // If running in MG, convert site.E to group
  if (!settings::run_CE) {
    site.E = lower_bound_index(data::mg.rev_energy_bins_.begin(),
      data::mg.rev_energy_bins_.end(), site.E);
    site.E = data::mg.num_energy_groups_ - site.E - 1.;
  }

  return site;
}

void free_memory_source()
{
  model::external_sources.clear();
}

void fill_source_bank_fixedsource()
{
  if (settings::path_source.empty() && settings::path_source_library.empty()) {
    for (int64_t i = 0; i < simulation::work_per_rank; ++i) {
      // initialize random number seed
      int64_t id = (simulation::total_gen + overall_generation()) *
        settings::n_particles + simulation::work_index[mpi::rank] + i + 1;
      uint64_t seed = init_seed(id, STREAM_SOURCE);

      // sample external source distribution
      simulation::source_bank[i] = sample_external_source(&seed);
    }
  } else if (settings::path_source.empty() && !settings::path_source.empty()) {
     std::stringstream msg;

    // Open the library
    void* source_library = dlopen(settings::path_source_library.c_str(),RTLD_LAZY);
    if(!source_library) {
      std::stringstream msg("Couldn't open source library " + settings::path_source_library);
      fatal_error(msg);
    }

    // load the symbol
    typedef Particle::Bank (*sample_t)(uint64_t seed);

    // reset errors
    dlerror();

    // get the function from the library
    sample_t sample_source = (sample_t) dlsym(source_library, "sample_source");
    const char *dlsym_error = dlerror();

    // check for any dlsym errors
    if (dlsym_error) {
      std::cout << dlsym_error << std::endl;
      dlclose(source_library);
      fatal_error("Couldn't open the sample_source symbol");
    }

    // Generation source sites from specified distribution in the
    // library source
    for (int64_t i = 0; i < simulation::work_per_rank; ++i) {
      // initialize random number seed
      int64_t id = simulation::total_gen*settings::n_particles +
        simulation::work_index[mpi::rank] + i + 1;
      uint64_t seed = init_seed(id, STREAM_SOURCE);

      // sample external source distribution
      simulation::source_bank[i] = sample_source(seed);
    }

    // release the library
    dlclose(source_library);
  }
}

} // namespace openmc
<commit_msg>line removal from review<commit_after>#include "openmc/source.h"

#include <algorithm> // for move
#include <sstream> // for stringstream

#if defined (__unix__) || (defined (__APPLE__) && defined (__MACH__))
#include <dlfcn.h> // for dlopen
#endif

#include <fmt/core.h>
#include "xtensor/xadapt.hpp"

#include "openmc/bank.h"
#include "openmc/cell.h"
#include "openmc/error.h"
#include "openmc/file_utils.h"
#include "openmc/hdf5_interface.h"
#include "openmc/material.h"
#include "openmc/message_passing.h"
#include "openmc/mgxs_interface.h"
#include "openmc/nuclide.h"
#include "openmc/capi.h"
#include "openmc/random_lcg.h"
#include "openmc/search.h"
#include "openmc/settings.h"
#include "openmc/simulation.h"
#include "openmc/state_point.h"
#include "openmc/xml_interface.h"

namespace openmc {

//==============================================================================
// Global variables
//==============================================================================

namespace model {

std::vector<SourceDistribution> external_sources;

}

//==============================================================================
// SourceDistribution implementation
//==============================================================================

SourceDistribution::SourceDistribution(UPtrSpace space, UPtrAngle angle, UPtrDist energy)
  : space_{std::move(space)}, angle_{std::move(angle)}, energy_{std::move(energy)} { }

SourceDistribution::SourceDistribution(pugi::xml_node node)
{
  // Check for particle type
  if (check_for_node(node, "particle")) {
    auto temp_str = get_node_value(node, "particle", true, true);
    if (temp_str == "neutron") {
      particle_ = Particle::Type::neutron;
    } else if (temp_str == "photon") {
      particle_ = Particle::Type::photon;
      settings::photon_transport = true;
    } else {
      fatal_error(std::string("Unknown source particle type: ") + temp_str);
    }
  }

  // Check for source strength
  if (check_for_node(node, "strength")) {
    strength_ = std::stod(get_node_value(node, "strength"));
  }

  // Check for external source file
  if (check_for_node(node, "file")) {
    // Copy path of source file
    settings::path_source = get_node_value(node, "file", false, true);

    // Check if source file exists
    if (!file_exists(settings::path_source)) {
      fatal_error(fmt::format("Source file '{}' does not exist.",
        settings::path_source));
    }
  } else if (check_for_node(node, "library")) {
     settings::path_source_library = get_node_value(node, "library", false, true);
     // check if it exists
     if (!file_exists(settings::path_source_library)) {
      	std::stringstream msg;
      	msg << "Library file " << settings::path_source_library << "' does not exist.";
	      fatal_error(msg);
     }
  } else {

    // Spatial distribution for external source
    if (check_for_node(node, "space")) {
      // Get pointer to spatial distribution
      pugi::xml_node node_space = node.child("space");

      // Check for type of spatial distribution and read
      std::string type;
      if (check_for_node(node_space, "type"))
        type = get_node_value(node_space, "type", true, true);
      if (type == "cartesian") {
        space_ = UPtrSpace{new CartesianIndependent(node_space)};
      } else if (type == "cylindrical") {
        space_ = UPtrSpace{new CylindricalIndependent(node_space)};
      } else if (type == "spherical") {
        space_ = UPtrSpace{new SphericalIndependent(node_space)};
      } else if (type == "box") {
        space_ = UPtrSpace{new SpatialBox(node_space)};
      } else if (type == "fission") {
        space_ = UPtrSpace{new SpatialBox(node_space, true)};
      } else if (type == "point") {
        space_ = UPtrSpace{new SpatialPoint(node_space)};
      } else {
        fatal_error(fmt::format(
          "Invalid spatial distribution for external source: {}", type));
      }

    } else {
      // If no spatial distribution specified, make it a point source
      space_ = UPtrSpace{new SpatialPoint()};
    }

    // Determine external source angular distribution
    if (check_for_node(node, "angle")) {
      // Get pointer to angular distribution
      pugi::xml_node node_angle = node.child("angle");

      // Check for type of angular distribution
      std::string type;
      if (check_for_node(node_angle, "type"))
        type = get_node_value(node_angle, "type", true, true);
      if (type == "isotropic") {
        angle_ = UPtrAngle{new Isotropic()};
      } else if (type == "monodirectional") {
        angle_ = UPtrAngle{new Monodirectional(node_angle)};
      } else if (type == "mu-phi") {
        angle_ = UPtrAngle{new PolarAzimuthal(node_angle)};
      } else {
        fatal_error(fmt::format(
          "Invalid angular distribution for external source: {}", type));
      }

    } else {
      angle_ = UPtrAngle{new Isotropic()};
    }

    // Determine external source energy distribution
    if (check_for_node(node, "energy")) {
      pugi::xml_node node_dist = node.child("energy");
      energy_ = distribution_from_xml(node_dist);
    } else {
      // Default to a Watt spectrum with parameters 0.988 MeV and 2.249 MeV^-1
      energy_ = UPtrDist{new Watt(0.988e6, 2.249e-6)};
    }
  }
}

Particle::Bank SourceDistribution::sample(uint64_t* seed) const
{
  Particle::Bank site;

  // Set weight to one by default
  site.wgt = 1.0;

  // Repeat sampling source location until a good site has been found
  bool found = false;
  int n_reject = 0;
  static int n_accept = 0;
  while (!found) {
    // Set particle type
    site.particle = particle_;

    // Sample spatial distribution
    site.r = space_->sample(seed);
    double xyz[] {site.r.x, site.r.y, site.r.z};

    // Now search to see if location exists in geometry
    int32_t cell_index, instance;
    int err = openmc_find_cell(xyz, &cell_index, &instance);
    found = (err != OPENMC_E_GEOMETRY);

    // Check if spatial site is in fissionable material
    if (found) {
      auto space_box = dynamic_cast<SpatialBox*>(space_.get());
      if (space_box) {
        if (space_box->only_fissionable()) {
          // Determine material
          const auto& c = model::cells[cell_index];
          auto mat_index = c->material_.size() == 1
            ? c->material_[0] : c->material_[instance];

          if (mat_index == MATERIAL_VOID) {
            found = false;
          } else {
            if (!model::materials[mat_index]->fissionable_) found = false;
          }
        }
      }
    }

    // Check for rejection
    if (!found) {
      ++n_reject;
      if (n_reject >= EXTSRC_REJECT_THRESHOLD &&
          static_cast<double>(n_accept)/n_reject <= EXTSRC_REJECT_FRACTION) {
        fatal_error("More than 95% of external source sites sampled were "
                    "rejected. Please check your external source definition.");
      }
    }
  }

  // Increment number of accepted samples
  ++n_accept;

  // Sample angle
  site.u = angle_->sample(seed);

  // Check for monoenergetic source above maximum particle energy
  auto p = static_cast<int>(particle_);
  auto energy_ptr = dynamic_cast<Discrete*>(energy_.get());
  if (energy_ptr) {
    auto energies = xt::adapt(energy_ptr->x());
    if (xt::any(energies > data::energy_max[p])) {
      fatal_error("Source energy above range of energies of at least "
                  "one cross section table");
    } else if (xt::any(energies < data::energy_min[p])) {
      fatal_error("Source energy below range of energies of at least "
                  "one cross section table");
    }
  }

  while (true) {
    // Sample energy spectrum
    site.E = energy_->sample(seed);

    // Resample if energy falls outside minimum or maximum particle energy
    if (site.E < data::energy_max[p] && site.E > data::energy_min[p]) break;
  }

  // Set delayed group
  site.delayed_group = 0;

  return site;
}

//==============================================================================
// Non-member functions
//==============================================================================

void initialize_source()
{
  write_message("Initializing source particles...", 5);

  if (settings::path_source != "") {
    // Read the source from a binary file instead of sampling from some
    // assumed source distribution

    write_message(fmt::format("Reading source file from {}...",
      settings::path_source), 6);

    // Open the binary file
    hid_t file_id = file_open(settings::path_source, 'r', true);

    // Read the file type
    std::string filetype;
    read_attribute(file_id, "filetype", filetype);

    // Check to make sure this is a source file
    if (filetype != "source" && filetype != "statepoint") {
      fatal_error("Specified starting source file not a source file type.");
    }

    // Read in the source bank
    read_source_bank(file_id);

    // Close file
    file_close(file_id);
  } else if ( settings::path_source_library != "" ) {
    // Get the source from a library object
    std::stringstream msg;
    msg << "Sampling from library source " << settings::path_source << "...";
    write_message(msg, 6);

    #if defined (__unix__) || (defined (__APPLE__) && defined (__MACH__))
    // Open the library
    void* source_library = dlopen(settings::path_source_library.c_str(),RTLD_LAZY);
    if(!source_library) {
      std::stringstream msg("Couldn't open source library " + settings::path_source_library);
      fatal_error(msg);
    }
    #else
    std::stringstream msg("This feature has not yet been implemented for non POSIX systems");
    fatal_error(msg);
    #endif

    // load the symbol
    typedef Particle::Bank (*sample_t)(uint64_t seed);

    // reset errors
    dlerror();

    // get the function from the library
    sample_t sample_source = (sample_t) dlsym(source_library, "sample_source");
    const char *dlsym_error = dlerror();

    // check for any dlsym errors
    if (dlsym_error) {
      std::cout << dlsym_error << std::endl;
      dlclose(source_library);
      fatal_error("Couldn't open the sample_source symbol");
    }

    // Generation source sites from specified distribution in the
    // library source
    for (int64_t i = 0; i < simulation::work_per_rank; ++i) {
      // initialize random number seed
      int64_t id = simulation::total_gen*settings::n_particles +
        simulation::work_index[mpi::rank] + i + 1;
      uint64_t seed = init_seed(id, STREAM_SOURCE);

      // sample external source distribution
      simulation::source_bank[i] = sample_source(seed);
    }
    // release the library
    dlclose(source_library);

  } else {
    // Generation source sites from specified distribution in user input
    for (int64_t i = 0; i < simulation::work_per_rank; ++i) {
      // initialize random number seed
      int64_t id = simulation::total_gen*settings::n_particles +
        simulation::work_index[mpi::rank] + i + 1;
      uint64_t seed = init_seed(id, STREAM_SOURCE);

      // sample external source distribution
      simulation::source_bank[i] = sample_external_source(&seed);
    }
  }

  // Write out initial source
  if (settings::write_initial_source) {
    write_message("Writing out initial source...", 5);
    std::string filename = settings::path_output + "initial_source.h5";
    hid_t file_id = file_open(filename, 'w', true);
    write_source_bank(file_id);
    file_close(file_id);
  }
}

Particle::Bank sample_external_source(uint64_t* seed)
{
  // Determine total source strength
  double total_strength = 0.0;
  for (auto& s : model::external_sources)
    total_strength += s.strength();

  // Sample from among multiple source distributions
  int i = 0;
  if (model::external_sources.size() > 1) {
    double xi = prn(seed)*total_strength;
    double c = 0.0;
    for (; i < model::external_sources.size(); ++i) {
      c += model::external_sources[i].strength();
      if (xi < c) break;
    }
  }

  // Sample source site from i-th source distribution
  Particle::Bank site {model::external_sources[i].sample(seed)};

  // If running in MG, convert site.E to group
  if (!settings::run_CE) {
    site.E = lower_bound_index(data::mg.rev_energy_bins_.begin(),
      data::mg.rev_energy_bins_.end(), site.E);
    site.E = data::mg.num_energy_groups_ - site.E - 1.;
  }

  return site;
}

void free_memory_source()
{
  model::external_sources.clear();
}

void fill_source_bank_fixedsource()
{
  if (settings::path_source.empty() && settings::path_source_library.empty()) {
    for (int64_t i = 0; i < simulation::work_per_rank; ++i) {
      // initialize random number seed
      int64_t id = (simulation::total_gen + overall_generation()) *
        settings::n_particles + simulation::work_index[mpi::rank] + i + 1;
      uint64_t seed = init_seed(id, STREAM_SOURCE);

      // sample external source distribution
      simulation::source_bank[i] = sample_external_source(&seed);
    }
  } else if (settings::path_source.empty() && !settings::path_source.empty()) {
     std::stringstream msg;

    // Open the library
    void* source_library = dlopen(settings::path_source_library.c_str(),RTLD_LAZY);
    if(!source_library) {
      std::stringstream msg("Couldn't open source library " + settings::path_source_library);
      fatal_error(msg);
    }

    // load the symbol
    typedef Particle::Bank (*sample_t)(uint64_t seed);

    // reset errors
    dlerror();

    // get the function from the library
    sample_t sample_source = (sample_t) dlsym(source_library, "sample_source");
    const char *dlsym_error = dlerror();

    // check for any dlsym errors
    if (dlsym_error) {
      std::cout << dlsym_error << std::endl;
      dlclose(source_library);
      fatal_error("Couldn't open the sample_source symbol");
    }

    // Generation source sites from specified distribution in the
    // library source
    for (int64_t i = 0; i < simulation::work_per_rank; ++i) {
      // initialize random number seed
      int64_t id = simulation::total_gen*settings::n_particles +
        simulation::work_index[mpi::rank] + i + 1;
      uint64_t seed = init_seed(id, STREAM_SOURCE);

      // sample external source distribution
      simulation::source_bank[i] = sample_source(seed);
    }

    // release the library
    dlclose(source_library);
  }
}

} // namespace openmc
<|endoftext|>