#include "math/SpatialDiscretization/FiniteElement/PiecewiseLinear/pwlc.h"
#include "physics/FieldFunction/fieldfunction2.h"
#include "chi_lua.h"
int main(
int argc,
char* argv[])
{
chi::Initialize(argc,argv);
chi::RunBatch(argc, argv);
const std::string fname = "Tutorial_07";
if (chi::mpi.process_count != 1)
throw std::logic_error(fname + ": Is serial only.");
const auto& grid = *grid_ptr;
chi::log.Log() << "Global num cells: " << grid.GetGlobalNumberOfCells();
const auto ijk_info = grid.GetIJKInfo();
const auto& ijk_mapping = grid.MakeIJKToGlobalIDMapping();
const auto Nx = static_cast<int64_t>(ijk_info[0]);
const auto Ny = static_cast<int64_t>(ijk_info[1]);
const auto Nz = static_cast<int64_t>(ijk_info[2]);
int dimension = 0;
if (grid.Attributes() & Dim1) dimension = 1;
if (grid.Attributes() & Dim2) dimension = 2;
if (grid.Attributes() & Dim3) dimension = 3;
typedef std::shared_ptr<chi_math::SpatialDiscretization>
SDMPtr;
SDMPtr sdm_ptr = chi_math::SpatialDiscretization_PWLD::New(grid_ptr);
const auto& sdm = *sdm_ptr;
const auto& OneDofPerNode = sdm.UNITARY_UNKNOWN_MANAGER;
const size_t num_local_nodes = sdm.GetNumLocalDOFs(OneDofPerNode);
const size_t num_globl_nodes = sdm.GetNumGlobalDOFs(OneDofPerNode);
chi::log.Log() << "Num local nodes: " << num_local_nodes;
chi::log.Log() << "Num globl nodes: " << num_globl_nodes;
std::shared_ptr<chi_math::AngularQuadrature> quadrature;
if (dimension == 1)
quadrature = std::make_shared<chi_math::AngularQuadratureProdGL>(8);
else if (dimension == 2)
{
quadrature = std::make_shared<chi_math::AngularQuadratureProdGLC>(8,8);
quadrature->OptimizeForPolarSymmetry(4.0*M_PI);
}
else if (dimension == 3)
quadrature = std::make_shared<chi_math::AngularQuadratureProdGLC>(8,8);
else
throw std::logic_error(fname + "Error with the dimensionality "
"of the mesh.");
chi::log.Log() << "Quadrature created." << std::endl;
const size_t scat_order = 1;
const size_t num_groups = 20;
quadrature->BuildMomentToDiscreteOperator(scat_order,dimension);
quadrature->BuildDiscreteToMomentOperator(scat_order,dimension);
const auto& m2d = quadrature->GetMomentToDiscreteOperator();
const auto& d2m = quadrature->GetDiscreteToMomentOperator();
const auto& m_ell_em_map = quadrature->GetMomentToHarmonicsIndexMap();
const size_t num_moments = m_ell_em_map.size();
const size_t num_dirs = quadrature->omegas.size();
chi::log.Log() << "End Set/Get params." << std::endl;
chi::log.Log() << "Num Moments: " << num_moments << std::endl;
std::vector<Unknown> phi_uks(num_moments, Unknown(VecN, num_groups));
std::vector<Unknown> psi_uks(num_dirs, Unknown(VecN, num_groups));
const size_t num_local_phi_dofs = sdm.GetNumLocalDOFs(phi_uk_man);
const size_t num_local_psi_dofs = sdm.GetNumLocalDOFs(psi_uk_man);
chi::log.Log() << "End ukmanagers." << std::endl;
chi_physics::TransportCrossSections xs;
xs.MakeFromCHIxsFile("tests/xs_graphite_pure.cxs");
std::vector<double> phi_old(num_local_phi_dofs,0.0);
std::vector<double> psi_old(num_local_psi_dofs, 0.0);
auto source_moments = phi_old;
auto phi_new = phi_old;
auto q_source = phi_old;
chi::log.Log() << "End vectors." << std::endl;
for (const auto& cell : grid.local_cells)
{
const auto& cc = cell.centroid;
const auto& cell_mapping = sdm.GetCellMapping(cell);
const size_t num_nodes = cell_mapping.NumNodes();
if (cc.x < 0.5 and cc.y < 0.5 and cc.z < 0.5 and
cc.x >-0.5 and cc.y >-0.5 and cc.z >-0.5)
{
for (size_t i=0; i<num_nodes; ++i)
{
const int64_t dof_map = sdm.MapDOFLocal(cell,i,phi_uk_man,0,0);
q_source[dof_map] = 1.0;
}
}
}
typedef std::vector<VecVec3>
MatVec3;
typedef std::vector<double>
VecDbl;
typedef std::vector<VecDbl>
MatDbl;
typedef std::vector<MatDbl> VecMatDbl;
std::vector<MatVec3> cell_Gmatrices;
std::vector<MatDbl> cell_Mmatrices;
std::vector<VecMatDbl> cell_faceMmatrices;
for (const auto& cell : grid.local_cells)
{
const auto& cell_mapping = sdm.GetCellMapping(cell);
const size_t num_nodes = cell_mapping.NumNodes();
const auto vol_qp_data = cell_mapping.MakeVolumeQuadraturePointData();
MatVec3 IntV_shapeI_gradshapeJ(num_nodes,
VecVec3(num_nodes,Vec3(0,0,0)));
MatDbl IntV_shapeI_shapeJ(num_nodes,
VecDbl(num_nodes,0.0));
for (unsigned int i = 0; i < num_nodes; ++i)
for (unsigned int j = 0; j < num_nodes; ++j)
for (const auto& qp : vol_qp_data.QuadraturePointIndices())
{
IntV_shapeI_gradshapeJ[i][j]
+= vol_qp_data.ShapeValue(i, qp) *
vol_qp_data.ShapeGrad(j, qp) *
vol_qp_data.JxW(qp);
IntV_shapeI_shapeJ[i][j]
+= vol_qp_data.ShapeValue(i, qp) *
vol_qp_data.ShapeValue(j, qp) *
vol_qp_data.JxW(qp);
}
cell_Gmatrices.push_back(std::move(IntV_shapeI_gradshapeJ));
cell_Mmatrices.push_back(std::move(IntV_shapeI_shapeJ));
const size_t num_faces = cell.faces.size();
VecMatDbl faces_Mmatrices;
for (size_t f=0; f<num_faces; ++f)
{
const auto face_qp_data = cell_mapping.MakeFaceQuadraturePointData(f);
for (unsigned int i = 0; i < num_nodes; ++i)
for (unsigned int j = 0; j < num_nodes; ++j)
for (const auto& qp : face_qp_data.QuadraturePointIndices())
IntS_shapeI_shapeJ[i][j]
+= face_qp_data.ShapeValue(i, qp) *
face_qp_data.ShapeValue(j, qp) *
face_qp_data.JxW(qp);
faces_Mmatrices.push_back(std::move(IntS_shapeI_shapeJ));
}
cell_faceMmatrices.push_back(std::move(faces_Mmatrices));
}
chi::log.Log() << "End cell matrices." << std::endl;
const auto cell_adj_mapping = sdm.MakeInternalFaceNodeMappings();
&num_moments,
&phi_uk_man, &psi_uk_man,
&m2d,&d2m,
&phi_new, &source_moments, &psi_old,
&cell_Gmatrices, &cell_Mmatrices, &cell_faceMmatrices,
&cell_adj_mapping]
(const std::array<int64_t,3>& ijk,
const Vec3& omega,
const size_t d,
const chi_physics::TransportCrossSections& cell_xs)
{
const auto cell_global_id = ijk_mapping.MapNDtoLin(ijk[1],ijk[0],ijk[2]);
const auto& cell = grid.cells[cell_global_id];
const auto cell_local_id = cell.local_id;
const auto& cell_mapping = sdm.GetCellMapping(cell);
const size_t num_nodes = cell_mapping.NumNodes();
const size_t num_faces = cell.faces.size();
const std::vector<double> zero_vector(num_groups,0.0);
const auto& G = cell_Gmatrices[cell_local_id];
const auto& M = cell_Mmatrices[cell_local_id];
for (size_t i = 0; i < num_nodes; ++i)
for (size_t j = 0; j < num_nodes; ++j)
A[i][j] = omega.Dot(G[i][j]);
for (size_t f=0; f<num_faces; ++f)
{
const auto& face = cell.faces[f];
const double mu = omega.Dot(face.normal);
if (mu < 0.0)
{
const auto& M_surf = cell_faceMmatrices[cell_local_id][f];
const size_t num_face_nodes = cell_mapping.NumFaceNodes(f);
for (size_t fi=0; fi<num_face_nodes; ++fi)
{
const int i = cell_mapping.MapFaceNode(f,fi);
for (size_t fj=0; fj<num_face_nodes; ++fj)
{
const int j = cell_mapping.MapFaceNode(f,fj);
const double* upwind_psi = zero_vector.data();
if (face.has_neighbor)
{
const auto& adj_cell = grid.cells[face.neighbor_id];
const int aj = cell_adj_mapping[cell.local_id][f][fj];
const int64_t ajmap = sdm.MapDOFLocal(adj_cell,aj,psi_uk_man,d,0);
upwind_psi = &psi_old[ajmap];
}
const double mu_Nij = -mu * M_surf[i][j];
A[i][j] += mu_Nij;
for (int g=0; g<num_groups; ++g)
b[g][i] += upwind_psi[g]*mu_Nij;
}
}
}
}
for (size_t g=0; g<num_groups; ++g)
{
auto Atemp = A;
VecDbl source(num_nodes, 0.0);
for (size_t i=0; i<num_nodes; ++i)
{
double temp_src = 0.0;
for (size_t m=0; m<num_moments; ++m)
{
const int64_t dof_map = sdm.MapDOFLocal(cell,i,phi_uk_man,m,g);
temp_src += m2d[m][d]*source_moments[dof_map];
}
source[i] = temp_src;
}
const double sigma_tg = cell_xs.sigma_t[g];
for (int i = 0; i < num_nodes; ++i)
{
double temp = 0.0;
for (int j = 0; j < num_nodes; ++j)
{
const double Mij = M[i][j];
Atemp[i][j] = A[i][j] + Mij*sigma_tg;
temp += Mij*source[j];
}
b[g][i] += temp;
}
}
for (size_t m=0; m<num_moments; ++m)
{
const double wn_d2m = d2m[m][d];
for (size_t i=0; i<num_nodes; ++i)
{
const int64_t dof_map = sdm.MapDOFLocal(cell,i,phi_uk_man,m,0);
for (size_t g=0; g<num_groups; ++g)
phi_new[dof_map + g] += wn_d2m * b[g][i];
}
}
for (size_t i=0; i<num_nodes; ++i)
{
const int64_t dof_map = sdm.MapDOFLocal(cell,i,psi_uk_man,d,0);
for (size_t g=0; g<num_groups; ++g)
psi_old[dof_map + g] = b[g][i];
}
};
auto Sweep = [&num_dirs,&quadrature,Nx,Ny,Nz,&
SweepChunk,&xs]()
{
for (size_t d=0; d<num_dirs; ++d)
{
const auto &omega = quadrature->omegas[d];
const auto &weight = quadrature->weights[d];
std::vector<int64_t> iorder, jorder, korder;
if (omega.x > 0.0) iorder = chi_math::Range<int64_t>(0, Nx);
else iorder = chi_math::Range<int64_t>(Nx - 1, -1, -1);
if (omega.y > 0.0) jorder = chi_math::Range<int64_t>(0, Ny);
else jorder = chi_math::Range<int64_t>(Ny - 1, -1, -1);
if (omega.z > 0.0) korder = chi_math::Range<int64_t>(0, Nz);
else korder = chi_math::Range<int64_t>(Nz - 1, -1, -1);
for (auto i: iorder)
for (auto j: jorder)
for (auto k: korder)
}
};
auto SetSource = [&source_moments, &phi_old, &q_source, &grid, &sdm,
&m_ell_em_map, &xs, num_moments,
&phi_uk_man]()
{
for (const auto& cell : grid.local_cells)
{
const auto& cell_mapping = sdm.GetCellMapping(cell);
const size_t num_nodes = cell_mapping.NumNodes();
const auto& S = xs.transfer_matrices;
for (size_t i=0; i<num_nodes; ++i)
{
for (size_t m=0; m<num_moments; ++m)
{
const int64_t dof_map = sdm.MapDOFLocal(cell,i,phi_uk_man,m,0);
const auto ell = m_ell_em_map[m].ell;
for (size_t g=0; g<num_groups; ++g)
{
source_moments[dof_map + g] = q_source[dof_map + g];
if (ell < S.size())
{
double inscat_g = 0.0;
for (const auto& [row_g, gprime, sigma_sm] : S[ell].Row(g))
inscat_g += sigma_sm * phi_old[dof_map + gprime];
source_moments[dof_map + g] += inscat_g;
}
}
}
}
}
};
auto ComputeRelativePWChange = [&grid,&sdm,
&num_moments,
&phi_uk_man]
(const std::vector<double>& in_phi_new,
const std::vector<double>& in_phi_old)
{
double pw_change = 0.0;
for (const auto& cell : grid.local_cells)
{
const auto& cell_mapping = sdm.GetCellMapping(cell);
const size_t num_nodes = cell_mapping.NumNodes();
for (size_t i=0; i<num_nodes; ++i)
{
const int64_t m0_map = sdm.MapDOFLocal(cell,i,phi_uk_man,0,0);
const double* phi_new_m0 = &in_phi_new[m0_map];
const double* phi_old_m0 = &in_phi_old[m0_map];
for (size_t m=0; m<num_moments; ++m)
{
const int64_t m_map = sdm.MapDOFLocal(cell,i,phi_uk_man,m,0);
const double* phi_new_m = &in_phi_new[m_map];
const double* phi_old_m = &in_phi_old[m_map];
for (size_t g=0; g<num_groups; ++g)
{
const double abs_phi_new_g_m0 = std::fabs(phi_new_m0[g]);
const double abs_phi_old_g_m0 = std::fabs(phi_old_m0[g]);
const double max_denominator = std::max(abs_phi_new_g_m0,
abs_phi_old_g_m0);
const double delta_phi = std::fabs(phi_new_m[g] - phi_old_m[g]);
if (max_denominator >= std::numeric_limits<double>::min())
pw_change = std::max(delta_phi/max_denominator,pw_change);
else
pw_change = std::max(delta_phi,pw_change);
}
}
}
}
return pw_change;
};
chi::log.Log() << "Starting iterations" << std::endl;
for (size_t iter=0; iter<200; ++iter)
{
phi_new.assign(phi_new.size(), 0.0);
SetSource();
Sweep();
const double rel_change = ComputeRelativePWChange(phi_new, phi_old);
std::stringstream outstr;
outstr << "Iteration " << std::setw(5) << iter << " ";
{
char buffer[100];
sprintf(buffer, "%11.3e\n", rel_change);
outstr << buffer;
}
chi::log.Log() << outstr.str();
phi_old = phi_new;
if (rel_change < 1.0e-6 and iter > 0)
break;
}
std::vector<std::shared_ptr<chi_physics::FieldFunction>> ff_list;
ff_list.push_back(std::make_shared<chi_physics::FieldFunction>(
"Phi",
sdm_ptr,
));
const std::vector<std::string> dim_strings = {"x","y","z"};
for (const std::string& dim : dim_strings)
ff_list.push_back(std::make_shared<chi_physics::FieldFunction>(
"J-"+dim,
sdm_ptr,
));
const size_t num_m0_dofs = sdm.GetNumLocalDOFs(m0_uk_man);
std::vector<double> m0_phi(num_m0_dofs, 0.0);
std::vector<double> mx_phi(num_m0_dofs, 0.0);
std::vector<double> my_phi(num_m0_dofs, 0.0);
std::vector<double> mz_phi(num_m0_dofs, 0.0);
sdm.CopyVectorWithUnknownScope(phi_old,
m0_phi,
phi_uk_man,
0,
m0_uk_man,
0);
ff_list[0]->UpdateFieldVector(m0_phi);
std::array<unsigned int,3> j_map = {0,0,0};
if (dimension == 1 and num_moments >= 2) j_map = {0,0,1};
if (dimension == 2 and num_moments >= 3) j_map = {2,1,0};
if (dimension == 3 and num_moments >= 4) j_map = {3,1,2};
sdm.CopyVectorWithUnknownScope(
phi_old, mx_phi, phi_uk_man, j_map[0], m0_uk_man, 0);
sdm.CopyVectorWithUnknownScope(
phi_old, my_phi, phi_uk_man, j_map[1], m0_uk_man, 0);
sdm.CopyVectorWithUnknownScope(
phi_old, mz_phi, phi_uk_man, j_map[2], m0_uk_man, 0);
ff_list[1]->UpdateFieldVector(mx_phi);
ff_list[2]->UpdateFieldVector(my_phi);
ff_list[3]->UpdateFieldVector(mz_phi);
chi_physics::FieldFunction::FFList const_ff_list;
for (const auto& ff_ptr : ff_list)
const_ff_list.push_back(ff_ptr);
chi_physics::FieldFunction::ExportMultipleToVTK("SimTest_91a_PWLD",
const_ff_list);
chi::Finalize();
return 0;
}
std::vector< VecDbl > MatDbl
std::vector< double > VecDbl
int main(int argc, char **argv)
chi_mesh::MeshContinuumPtr & GetGrid() const
chi_mesh::sweep_management::SweepChunk SweepChunk
std::vector< chi_mesh::Vector3 > VecVec3
std::shared_ptr< SpatialDiscretization > SDMPtr
void GaussElimination(MatDbl &A, VecDbl &b, int n)
MeshHandler & GetCurrentHandler()
std::vector< VecVec3 > MatVec3