Commit d9f859dd authored by Tuelin Kaman's avatar Tuelin Kaman
Browse files

Space charge calculation for complicated 3D geometries

parent 42b385ee
......@@ -820,18 +820,13 @@ void PartBunch::computeSelfFields(int binNumber) {
}
void PartBunch::resizeMesh() {
double scaleFactor = 1.0;
//scaleFactor = (Physics::c * dt_m);
//get x, y range and scale to unit-less
double xmin = fs_m->solver_m->getXRangeMin() * scaleFactor ;
double xmax = fs_m->solver_m->getXRangeMax() * scaleFactor;
double ymin = fs_m->solver_m->getYRangeMin() * scaleFactor;
double ymax = fs_m->solver_m->getYRangeMax() * scaleFactor;
// Check if the new domain is larger than bunch max, mins
get_bounds(rmin_m, rmax_m);
//XXX: instead of assert delete oob particles!
double xmin = fs_m->solver_m->getXRangeMin();
double xmax = fs_m->solver_m->getXRangeMax();
double ymin = fs_m->solver_m->getYRangeMin();
double ymax = fs_m->solver_m->getYRangeMax();
double zmin = fs_m->solver_m->getZRangeMin();
double zmax = fs_m->solver_m->getZRangeMax();
if(xmin > rmin_m[0] || xmax < rmax_m[0] ||
ymin > rmin_m[1] || ymax < rmax_m[1]) {
......@@ -851,21 +846,15 @@ void PartBunch::resizeMesh() {
boundp();
get_bounds(rmin_m, rmax_m);
}
Vector_t mymin = Vector_t(xmin, ymin , zmin);
Vector_t mymax = Vector_t(xmax, ymax , zmax);
hr_m[0] = (xmax - xmin) / (nr_m[0]-1);
hr_m[1] = (ymax - ymin) / (nr_m[1]-1);
//hr_m[2] = (rmax_m[2] - rmin_m[2]) / (nr_m[2] - 1);
for(int i = 0; i < 3; i++)
hr_m[i] = (mymax[i] - mymin[i]) / nr_m[i];
// we cannot increase the number of mesh points
// this would require to delete and recreate the
// particle bunch since the FieldLayout is fixed
// in ParticleBase
Vector_t mymin = Vector_t(xmin, ymin, rmin_m[2]);
// rescale mesh
getMesh().set_meshSpacing(&(hr_m[0]));
getMesh().set_origin(mymin);
getMesh().set_origin(mymin);
rho_m.initialize(getMesh(),
getFieldLayout(),
......@@ -877,6 +866,8 @@ void PartBunch::resizeMesh() {
vbc_m);
update();
// setGridIsFixed();
}
void PartBunch::computeSelfFields() {
......@@ -886,8 +877,8 @@ void PartBunch::computeSelfFields() {
if(fs_m->hasValidSolver()) {
if(fs_m->getFieldSolverType() == "MG") // || fs_m->getFieldSolverType() == "FFTBOX") {
resizeMesh();
// if(fs_m->getFieldSolverType() == "SAAMG" && !isGridFixed())
// resizeMesh();
INFOMSG("after resizeMesh" << hr_m << endl);
//scatter charges onto grid
......@@ -911,7 +902,6 @@ void PartBunch::computeSelfFields() {
//divide charge by a 'grid-cube' volume to get [C/m^3]
rho_m *= tmp2;
// #define DBG_SCALARFIELD
#ifdef DBG_SCALARFIELD
INFOMSG("*** START DUMPING SCALAR FIELD ***" << endl);
ofstream fstr1;
......
......@@ -2648,8 +2648,10 @@ void ParallelTTracker::initializeBoundaryGeometry() {
for(unsigned int i = 0; i < itsOpalBeamline_m.sections_m.size(); i++) {
bgf_m = itsOpalBeamline_m.getBoundaryGeometry(i);
if(!bgf_m) continue;
if(!bgf_m)
continue;
else
break;
Distribution *dist = NULL;
Distribution *distrand = NULL;
vector<string> distr_str = bgf_m->getDistributionArray();
......
<
// ------------------------------------------------------------------------
// $Version: 1.2.1 $
// ------------------------------------------------------------------------
// Copyright & License: See Copyright.readme in src directory
// ------------------------------------------------------------------------
// Class ArbitraryDomain
// Interface to iterative solver and boundary geometry
// for space charge calculation
//
// ------------------------------------------------------------------------
// $Author: kaman $
// $Date: 2014 $
// ------------------------------------------------------------------------
#ifdef HAVE_SAAMG_SOLVER
#include <map>
#include <cmath>
......@@ -6,399 +20,306 @@
#include "ArbitraryDomain.h"
//IFF: simplified case where we have intersect = 2
//IFF: every node counts own number of gridpoints and then sum to global procs before MyPID (including ghost layers in z direction).
//IFF: triangles intersecting in z dir? (cathode?) -> boundary condition there? neumann? then we should take a normal and stuff!?
ArbitraryDomain::ArbitraryDomain(BoundaryGeometry * bgeom, Vector_t Geo_mincoords, Vector_t Geo_maxcoords, Vector_t nr, Vector_t hr, NDIndex<3> locidx, std::string interpl) {
bgeom_m=bgeom;
Geo_mincoords_m = bgeom->getmincoords();
Geo_maxcoords_m = bgeom->getmaxcoords();
setNr(nr);
setHr(hr);
localidx = locidx;
startIdx = 0;
std::cout << "Arbitrary domain TK localidx:" << localidx << std::endl;
std::cout << Geo_mincoords_m << std::endl;
std::cout << Geo_maxcoords_m << std::endl;
std::cout << "bgeom-maxcoords" << bgeom->getmaxcoords() << std::endl;
std::cout << "hr_m" << hr << std::endl;
if(interpl == "constant")
interpolationMethod = CONSTANT;
else if(interpl == "linear")
interpolationMethod = LINEAR;
else if(interpl == "quadratic")
interpolationMethod = QUADRATIC;
ArbitraryDomain::ArbitraryDomain(
BoundaryGeometry * bgeom,
Vector_t nr,
Vector_t hr,
std::string interpl) {
bgeom_m = bgeom;
Geo_mincoords_m = bgeom->getmincoords();
Geo_maxcoords_m = bgeom->getmaxcoords();
setNr(nr);
setHr(hr);
setMinMaxZ(Geo_mincoords_m[2],Geo_maxcoords_m[2]);
startId = 0;
if(interpl == "CONSTANT")
interpolationMethod = CONSTANT;
else if(interpl == "LINEAR")
interpolationMethod = LINEAR;
else if(interpl == "QUADRATIC")
interpolationMethod = QUADRATIC;
}
ArbitraryDomain::~ArbitraryDomain() {
//nothing so far
}
void ArbitraryDomain::Compute(Vector_t hr) {
void ArbitraryDomain::Compute(Vector_t hr, NDIndex<3> localId) {
setHr(hr);
int zGhostOffsetLeft = (localId[2].first()== 0) ? 0 : 1;
int zGhostOffsetRight = (localId[2].last() == nr[2] - 1) ? 0 : 1;
int yGhostOffsetLeft = (localId[1].first()== 0) ? 0 : 1;
int yGhostOffsetRight = (localId[1].last() == nr[1] - 1) ? 0 : 1;
int xGhostOffsetLeft = (localId[0].first()== 0) ? 0 : 1;
int xGhostOffsetRight = (localId[0].last() == nr[0] - 1) ? 0 : 1;
hasGeometryChanged_m = true;
//h5_float64_t edge1, edge2, t, q, p, P0;
double edge1[3], edge2[3], t[3], q[3], p[3], P0[3];
double det, invDet, u, v, tt;
double dir[3], origin[3];
int zGhostOffsetLeft = (localidx[2].first() == 0) ? 0 : 1;
int zGhostOffsetRight = (localidx[2].last() == nr[2] - 1) ? 0 : 1;
std::multimap< std::pair<int, int>, double >::iterator it;
std::pair< std::multimap< std::pair<int, int>, double>::iterator, std::multimap< std::pair<int, int>, double>::iterator > ret;
bool hit;
//forall triangles
int numbfaces = bgeom_m->getNumBFaces();
for (int i = 0; i < numbfaces ; i++) {
Vector_t x1 = bgeom_m->getVertexCoord(i, 1); //geo3Dcoords_m[allbfaces_m[4 * face_id + vertex_id]]
Vector_t x2 = bgeom_m->getVertexCoord(i, 2); //geo3Dcoords_m[allbfaces_m[4 * face_id + vertex_id]]
Vector_t x3 = bgeom_m->getVertexCoord(i, 3); //geo3Dcoords_m[allbfaces_m[4 * face_id + vertex_id]]
P0[0] = x2[0];
P0[1] = x2[1];
P0[2] = x2[2];
edge1[0] = x1[0] - x2[0];
edge1[1] = x1[1] - x2[1];
edge1[2] = x1[2] - x2[2];
edge2[0] = x3[0] - x2[0];
edge2[1] = x3[1] - x2[1];
edge2[2] = x3[2] - x2[2];
//IFF: use normed dir -> t = intersection (?)
//x dir rays = forall points in origin y,z with dir (1,0,0) (Y,Z -> COORD)
dir[0] = 1;
dir[1] = 0;
dir[2] = 0;
origin[0] = 0; //Geo_mincoords_m(0); //0;
origin[1] = 0; //Geo_mincoords_m(1); //0;
origin[2] = getMinZ(); //0;
for(int y = 0; y < nr[1]; y++) {
origin[1] = (y - (nr[1]-1)/2.0)*hr[1];
//ONE LAYER MORE = GHOST LAYER
for(int z = localidx[2].first() - zGhostOffsetLeft; z <= localidx[2].last() + zGhostOffsetRight; z++) {
origin[2] = getMinZ()+z * hr[2];
crossProduct(dir, edge2, p);
det = dotProduct(edge1, p);
if(det > -1e-5 && det < 1e-5)
continue;
invDet = 1.0 / det;
t[0] = origin[0] - P0[0];
t[1] = origin[1] - P0[1];
t[2] = origin[2] - P0[2];
u = dotProduct(t, p) * invDet;
if(u < 0.0 || u > 1.0)
continue;
crossProduct(t, edge1, q);
v = dotProduct(dir, q) * invDet;
if(v < 0.0 || u + v > 1.0)
continue;
//ray really intersects triangle
tt = dotProduct(edge2, q) * invDet;
//put intersection point in structure
std::pair<int, int> tmp(y, z);
//IntersectZDir[tmp] = tt;
hit = false;
ret = IntersectXDir.equal_range(tmp);
for(it = ret.first; it != ret.second; ++it)
hit = hit || (fabs(it->second - tt) < 1e-15);
if(!hit)
IntersectXDir.insert(std::pair< std::pair<int, int>, double >(tmp, tt));
IntersectLoX.clear();
IntersectHiX.clear();
IntersectLoY.clear();
IntersectHiY.clear();
IntersectLoZ.clear();
IntersectHiZ.clear();
//calculate intersection
Vector_t P, dir, I;
for (int idz = localId[2].first()-zGhostOffsetLeft; idz <= localId[2].last()+zGhostOffsetRight; idz++) {
P[2] = (idz - (nr[2]-1)/2.0)*hr[2];
for (int idy = localId[1].first()-yGhostOffsetLeft; idy <= localId[1].last()+yGhostOffsetRight; idy++) {
P[1] = (idy - (nr[1]-1)/2.0)*hr[1];
for (int idx = localId[0].first()-xGhostOffsetLeft; idx <= localId[0].last()+xGhostOffsetRight; idx++) {
P[0] = (idx - (nr[0]-1)/2.0)*hr[0];
std::tuple<int, int, int> pos(idx, idy, idz);
dir = Vector_t(0,0,1);
if (bgeom_m->intersectRayBoundary(P, dir, I))
IntersectHiZ.insert(std::pair< std::tuple<int, int, int>, double >(pos, I[2]));
dir = Vector_t(0,0,-1);
if (bgeom_m->intersectRayBoundary(P, dir, I))
IntersectLoZ.insert(std::pair< std::tuple<int, int, int>, double >(pos, I[2]));
dir = Vector_t(0,1,0);
if (bgeom_m->intersectRayBoundary(P, dir, I))
IntersectHiY.insert(std::pair< std::tuple<int, int, int>, double >(pos, I[1]));
dir = Vector_t(0,-1,0);
if (bgeom_m->intersectRayBoundary(P, dir, I))
IntersectLoY.insert(std::pair< std::tuple<int, int, int>, double >(pos, I[1]));
dir = Vector_t(1,0,0);
if (bgeom_m->intersectRayBoundary(P, dir, I))
IntersectHiX.insert(std::pair< std::tuple<int, int, int>, double >(pos, I[0]));
dir = Vector_t(-1,0,0);
if (bgeom_m->intersectRayBoundary(P, dir, I))
IntersectLoX.insert(std::pair< std::tuple<int, int, int>, double >(pos, I[0]));
}
}
}
//number of ghost nodes to the right
int znumGhostNodesRight = 0;
if(zGhostOffsetRight != 0) {
for(int idx = localId[0].first(); idx <= localId[0].last(); idx++) {
for(int idy = localId[1].first(); idy <= localId[1].last(); idy++) {
if(isInside(idx, idy, localId[2].last() + zGhostOffsetRight))
znumGhostNodesRight++;
}
}
}
//y dir rays = forall points in origin x,z with dir (0,1,0) (X,Z -> COORD)
dir[0] = 0;
dir[1] = 1;
dir[2] = 0;
origin[0] = 0;//Geo_mincoords_m(0); //0;
origin[1] = 0;//Geo_mincoords_m(1); //0;
origin[2] = getMinZ(); //0;
for(int x = 0; x < nr[0]; x++) {
origin[0] = (x - (nr[0]-1)/2.0)*hr[0];
//ONE LAYER MORE = GHOST LAYER
for(int z = localidx[2].first() - zGhostOffsetLeft; z <= localidx[2].last() + zGhostOffsetRight; z++) {
origin[2] = getMinZ() + z * hr[2];
crossProduct(dir, edge2, p);
det = dotProduct(edge1, p);
if(det > -1e-5 && det < 1e-5)
continue;
invDet = 1.0 / det;
t[0] = origin[0] - P0[0];
t[1] = origin[1] - P0[1];
t[2] = origin[2] - P0[2];
u = dotProduct(t, p) * invDet;
if(u < 0.0 || u > 1.0)
continue;
crossProduct(t, edge1, q);
v = dotProduct(dir, q) * invDet;
if(v < 0.0 || u + v > 1.0)
continue;
//ray really intersects triangle
tt = dotProduct(edge2, q) * invDet;
//put intersection point in structure
std::pair<int, int> tmp(x, z);
hit = false;
ret = IntersectYDir.equal_range(tmp);
for(it = ret.first; it != ret.second; ++it)
hit = hit || (fabs(it->second - tt) < 1e-15);
if(!hit)
IntersectYDir.insert(std::pair< std::pair<int, int>, double >(tmp, tt));
//number of ghost nodes to the left
int znumGhostNodesLeft = 0;
if(zGhostOffsetLeft != 0) {
for(int idx = localId[0].first(); idx <= localId[0].last(); idx++) {
for(int idy = localId[1].first(); idy <= localId[1].last(); idy++) {
if(isInside(idx, idy, localId[2].first() - zGhostOffsetLeft))
znumGhostNodesLeft++;
}
}
}
//z dir rays = forall points in origin x,y with dir (0,0,1) (X,Y -> COORD)
dir[0] = 0;
dir[1] = 0;
dir[2] = 1;
origin[0] = 0; //Geo_mincoords_m(0); //0;
origin[1] = 0; //Geo_mincoords_m(1); //0;
origin[2] = getMinZ(); //0;
for(int x = 0; x < nr[0]; x++) {
origin[0] = (x - (nr[0]-1)/2.0)*hr[0];
for(int y = 0; y < nr[1]; y++) {
origin[1] = (y - (nr[1]-1)/2.0)*hr[1];
crossProduct(dir, edge2, p);
det = dotProduct(edge1, p);
if(det > -1e-5 && det < 1e-5)
continue;
invDet = 1.0 / det;
t[0] = origin[0] - P0[0];
t[1] = origin[1] - P0[1];
t[2] = origin[2] - P0[2];
u = dotProduct(t, p) * invDet;
if(u < 0.0 || u > 1.0)
continue;
crossProduct(t, edge1, q);
v = dotProduct(dir, q) * invDet;
if(v < 0.0 || u + v > 1.0)
continue;
//ray really intersects triangle
tt = dotProduct(edge2, q) * invDet;
//put intersection point in structure
std::pair<int, int> tmp(x, y);
hit = false;
ret = IntersectZDir.equal_range(tmp);
for(it = ret.first; it != ret.second; ++it)
hit = hit || (fabs(it->second - tt) < 1e-15);
if(!hit)
IntersectZDir.insert(std::pair< std::pair<int, int>, double >(tmp, tt));
//number of ghost nodes to the right
int ynumGhostNodesRight = 0;
if(yGhostOffsetRight != 0) {
for(int idx = localId[0].first(); idx <= localId[0].last(); idx++) {
for(int idz = localId[2].first(); idz <= localId[2].last(); idz++) {
if(isInside(idx, localId[1].last() + yGhostOffsetRight, idz))
ynumGhostNodesRight++;
}
}
}
std::cout << "number of intersections in x-dir: " << IntersectXDir.size() << std::endl;
std::cout << "number of intersections in y-dir: " << IntersectYDir.size() << std::endl;
std::cout << "number of intersections in z-dir: " << IntersectZDir.size() << std::endl;
//number of ghost nodes to the left
int numGhostNodesLeft = 0;
if(localidx[2].first() != 0) {
for(int x = 0; x < nr[0]; x++) {
for(int y = 0; y < nr[1]; y++) {
//number of ghost nodes to the left
int ynumGhostNodesLeft = 0;
if(yGhostOffsetLeft != 0) {
for(int idx = localId[0].first(); idx <= localId[0].last(); idx++) {
for(int idz = localId[2].first(); idz <= localId[2].last(); idz++) {
if(isInside(idx, localId[1].first() - yGhostOffsetLeft, idz))
ynumGhostNodesLeft++;
}
}
}
if(isInside(x, y, localidx[2].first() - zGhostOffsetLeft))
numGhostNodesLeft++;
//number of ghost nodes to the right
int xnumGhostNodesRight = 0;
if(xGhostOffsetRight != 0) {
for (int idy = localId[1].first(); idy <= localId[1].last(); idy++) {
for (int idz = localId[2].first(); idz <= localId[2].last(); idz++) {
if(isInside(localId[0].last() + xGhostOffsetRight, idy, idz))
xnumGhostNodesRight++;
}
}
}
std::cout << "ghost nodes left: " << numGhostNodesLeft << std::endl;
//number of ghost nodes to the left
int xnumGhostNodesLeft = 0;
if(xGhostOffsetLeft != 0) {
for (int idy = localId[1].first(); idy <= localId[1].last(); idy++) {
for(int idz = localId[2].first(); idz <= localId[2].last(); idz++) {
if(isInside(localId[0].first() - xGhostOffsetLeft, idy, idz))
xnumGhostNodesLeft++;
}
}
}
//xy points in z plane
int numxy = 0;
int numtotal = 0;
numXY.clear();
for(int idx = localidx[2].first(); idx <= localidx[2].last(); idx++) {
numxy = 0;
for(int x = 0; x < nr[0]; x++) {
for(int y = 0; y < nr[1]; y++) {
int numxy;
int numtotalxy = 0;
if(isInside(x, y, idx))
numxy++;
numXY.clear();
for (int idz = localId[2].first(); idz <= localId[2].last(); idz++) {
numxy =0;
for (int idy = localId[1].first(); idy <= localId[1].last(); idy++) {
for (int idx =localId[0].first(); idx <= localId[0].last(); idx++) {
if (isInside(idx, idy, idz))
numxy++;
}
}
numXY[idx-localidx[2].first()] = numxy;
numtotal += numxy;
numtotalxy += numxy;
}
std::cout << "number of gridpoints: " << numtotal << std::endl;
startIdx = 0;
MPI_Scan(&numtotal, &startIdx, 1, MPI_INTEGER, MPI_SUM, Ippl::getComm());
startIdx -= numtotal;
startId = 0;
MPI_Scan(&numtotalxy, &startId, 1, MPI_INTEGER, MPI_SUM, Ippl::getComm());
std::cout << "start idx: " << startIdx << std::endl;
startId -= numtotalxy;
//build up index and coord map
IdxMap.clear();
CoordMap.clear();
register int idx = startIdx - numGhostNodesLeft;
std::cout << idx << std::endl;
for(int x = 0; x < nr[0]; x++) {
for(int y = 0; y < nr[1]; y++) {
for(int z = localidx[2].first() - zGhostOffsetLeft; z <= localidx[2].last() + zGhostOffsetRight; z++) {
if(isInside(x, y, z)) {
IdxMap[toCoordIdx(x, y, z)] = idx;
CoordMap[idx++] = toCoordIdx(x, y, z);
}
}
}
}
}
/// conversion from (x,y,z) to index in xyz plane
inline int ArbitraryDomain::toCoordIdx(int x, int y, int z) {
return (z * nr[1] + y) * nr[0] + x;
register int id = startId - xnumGhostNodesLeft - ynumGhostNodesLeft - znumGhostNodesLeft;
for (int idz = localId[2].first()-zGhostOffsetLeft; idz <= localId[2].last()+zGhostOffsetRight; idz++) {
for (int idy = localId[1].first()-yGhostOffsetLeft; idy <= localId[1].last()+yGhostOffsetRight; idy++) {
for (int idx = localId[0].first()-xGhostOffsetLeft; idx <= localId[0].last()+xGhostOffsetRight; idx++) {
if (isInside(idx, idy, idz)) {
IdxMap[toCoordIdx(idx, idy, idz)] = id;
CoordMap[id] = toCoordIdx(idx, idy, idz);
id++;
}
}
}
}
}
/// conversion from (x,y,z) to index on the 3D grid
/*inline*/
int ArbitraryDomain::getIdx(int x, int y, int z) {
if(isInside(x, y, z) && x >= 0 && y >= 0 && z >= 0)
return IdxMap[toCoordIdx(x, y, z)];
else
return -1;
// Conversion from (x,y,z) to index in xyz plane
inline int ArbitraryDomain::toCoordIdx(int idx, int idy, int idz) {
return (idz * nr[1] + idy) * nr[0] + idx;
}
// Conversion from (x,y,z) to index on the 3D grid
int ArbitraryDomain::getIdx(int idx, int idy, int idz) {
if(isInside(idx, idy, idz) && idx>=0 && idy >=0 && idz >=0 )
return IdxMap[toCoordIdx(idx, idy, idz)];
else
return -1;
}
/// conversion from a 3D index to (x,y,z)