/** * @file interface_particles.cpp * @author Julian Iseringhausen * @date Mon Apr 18 12:56:48 2011 * * @brief VMG::InterfaceParticles * */ #ifdef HAVE_CONFIG_H #include #endif #ifdef HAVE_MPI #include #ifdef HAVE_MARMOT #include #include #endif #endif #include #include #include "base/helper.hpp" #include "base/index.hpp" #include "base/interpolate_polynomial.hpp" #include "base/linked_cell_list.hpp" #include "base/math.hpp" #include "base/vector.hpp" #include "comm/comm.hpp" #include "grid/grid.hpp" #include "grid/multigrid.hpp" #include "grid/tempgrid.hpp" #include "interface/interface_particles.hpp" #include "mg.hpp" using namespace VMG; void InterfaceParticles::ImportRightHandSide(Multigrid& multigrid) { Index index_global, index_local, index; Vector pos_rel, pos_abs, grid_val; Factory& factory = MG::GetFactory(); Comm& comm = *MG::GetComm(); const int& near_field_cells = factory.GetObjectStorageVal("PARTICLE_NEAR_FIELD_CELLS"); Grid& grid = multigrid(multigrid.MaxLevel()); Grid& particle_grid = comm.GetParticleGrid(); particle_grid.Clear(); assert(particle_grid.Global().LocalSize().IsComponentwiseGreater(near_field_cells)); /* * Distribute particles to their processes */ particles.clear(); comm.CommParticles(grid, particles); /* * Charge assignment on the grid */ std::list::iterator iter; #ifdef DEBUG_OUTPUT vmg_float particle_charges = 0.0; for (iter=particles.begin(); iter!=particles.end(); ++iter) particle_charges += iter->Charge(); particle_charges = MG::GetComm()->GlobalSumRoot(particle_charges); comm.PrintStringOnce("Particle list charge sum: %e", particle_charges); comm.PrintString("Local number of particles: %d", particles.size()); #endif for (iter=particles.begin(); iter!=particles.end(); ++iter) spl.SetSpline(particle_grid, *iter, near_field_cells); // Communicate charges over halo comm.CommFromGhosts(particle_grid); // Assign charge values to the right hand side for (index.X()=0; index.X()GlobalSum(charge_sum); comm.PrintStringOnce("Grid charge sum: %e", charge_sum); #endif } void InterfaceParticles::ExportSolution(Grid& grid) { Index index; vmg_float length; Vector dist_vec; #ifdef DEBUG_OUTPUT vmg_float e = 0.0; vmg_float e_long = 0.0; vmg_float e_self = 0.0; vmg_float e_short = 0.0; vmg_float e_shortcorr = 0.0; #endif Factory& factory = MG::GetFactory(); Comm& comm = *MG::GetComm(); /* * Get parameters and arrays */ const vmg_int& num_particles_local = factory.GetObjectStorageVal("PARTICLE_NUM_LOCAL"); const vmg_int& near_field_cells = factory.GetObjectStorageVal("PARTICLE_NEAR_FIELD_CELLS"); const vmg_int& interpolation_degree = factory.GetObjectStorageVal("PARTICLE_INTERPOLATION_DEGREE"); vmg_float* p = factory.GetObjectStorageArray("PARTICLE_POTENTIAL_ARRAY"); vmg_float* f = factory.GetObjectStorageArray("PARTICLE_FIELD_ARRAY"); InterpolatePolynomial ip(interpolation_degree); const vmg_float r_cut = (near_field_cells+0.5) * grid.Extent().MeshWidth().Max(); /* * Initialize potential */ for (vmg_int i=0; i::iterator p_iter; for (p_iter=particles.begin(); p_iter!=particles.end(); ++p_iter) { const Index global_index = (p_iter->Pos() - particle_grid.Extent().Begin()) / particle_grid.Extent().MeshWidth(); const Index local_index = global_index - particle_grid.Global().LocalBegin() + particle_grid.Local().Begin(); ip.ComputeCoefficients(particle_grid, local_index); // Interpolate long range part of potential minus self-interaction p_iter->Pot() = ip.Evaluate(p_iter->Pos()) - p_iter->Charge() * spl.GetAntiDerivativeAtZero(); p_iter->Field() = ip.EvaluateGradient(p_iter->Pos()); #ifdef DEBUG_OUTPUT // TODO The scaling with 1/2 may not be correct. Check that. e_long += 0.5 * p_iter->Charge() * Helper::InterpolateTrilinear(p_iter->Pos(), particle_grid); e_self += 0.5 * p_iter->Charge() * p_iter->Charge() * spl.GetAntiDerivativeAtZero(); #endif } /* * Compute near field correction */ Particle::LinkedCellList lc(particles, near_field_cells, grid); Particle::LinkedCellList::iterator p1, p2; Grid::iterator iter; comm.CommLCListToGhosts(lc); for (iter=lc.Iterators().Local().Begin(); iter!=lc.Iterators().Local().End(); ++iter) { std::list& lc_1 = lc(*iter); for (p1=lc_1.begin(); p1!=lc_1.end(); ++p1) for (index.X()=-1*near_field_cells-1; index.X()<=near_field_cells+1; ++index.X()) for (index.Y()=-1*near_field_cells-1; index.Y()<=near_field_cells+1; ++index.Y()) for (index.Z()=-1*near_field_cells-1; index.Z()<=near_field_cells+1; ++index.Z()) { std::list& lc_2 = lc(*iter+index); for (p2=lc_2.begin(); p2!=lc_2.end(); ++p2) if (*p1 != *p2) { length = ((*p2)->Pos() - (*p1)->Pos()).Length(); //TODO Rewrite this equation more efficiently if (length < r_cut) { (*p1)->Pot() += (*p2)->Charge() / length * (1.0 + spl.EvaluatePotential(length)); #ifdef DEBUG_OUTPUT e_short += 0.5 * (*p1)->Charge() * (*p2)->Charge() / length; e_shortcorr -= 0.5 * (*p1)->Charge() * (*p2)->Charge() / length * spl.EvaluatePotential(length); #endif } } } } comm.CommParticlesBack(particles); #ifdef DEBUG_OUTPUT vmg_float* q = factory.GetObjectStorageArray("PARTICLE_CHARGE_ARRAY"); for (int i=0; i