BLCMDfieldlines Class Reference

Inheritance diagram for BLCMDfieldlines:

BLCommand BLCallback

List of all members.

Public Member Functions

 BLCMDfieldlines ()
G4String commandName ()
int command (BLArgumentVector &argv, BLArgumentMap &namedArgs)
void defineNamedArgs ()
bool isInWorld (G4ThreeVector &pos)
void generatePoints ()
void generateOneFieldLine (G4ThreeVector &point)
void callback (int type)
void Draw ()
double bmag (int i, int j)
G4ThreeVector point (int i, int j)
int excludeRadiusSq (double bmag)

Private Attributes

G4double t
G4String centerStr
G4double radius
G4int nLines
G4double dl
G4String color
G4double minField
G4int maxPoints
G4int subdivide
G4int N
G4int exit
G4int square
G4int Efield
G4int forever
G4ThreeVector center
std::vector< G4ThreeVector > points
std::vector< G4ThreeVector > argPoints
std::vector< G4Polyline > lines
BLVisManagervisManager
BLGlobalFieldfield
int ic
double dx
double scale
G4RotationMatrix * rot
double worldHalfHeight
double worldHalfWidth
double worldHalfLength


Constructor & Destructor Documentation

BLCMDfieldlines::BLCMDfieldlines (  ) 

References BLCMDTYPE_OTHER, centerStr, color, dl, dx, Efield, exit, field, forever, ic, maxPoints, minField, N, nLines, radius, BLCommand::registerCommand(), rot, scale, BLCommand::setDescription(), BLCommand::setSynopsis(), square, subdivide, t, visManager, worldHalfHeight, worldHalfLength, and worldHalfWidth.

Referenced by command().

00094                                  : BLCommand(), BLCallback(), 
00095                         G4VUserVisAction(), points(), argPoints(), lines()
00096 {
00097         registerCommand(BLCMDTYPE_OTHER);
00098         setSynopsis("Display magnetic field lines.");
00099         setDescription("Field lines are drawn starting within a circle "
00100         "specified as center and radius (global coordinates); the plane of "
00101         "the circle is normal to the B field at its center. Field lines "
00102         "are distributed within the circle "
00103         "with a density inversely proportional to |B|. While it is attempted "
00104         "to keep their spacing as uniform as possible, there are both "
00105         "ambiguity and randomness involved in placing the lines within the "
00106         "circle. Lines are placed within the circle from its center outward, "
00107         "and if |B|<minField then no more lines are placed.\n\n"
00108         "nLines is only approximate, and the actual number of lines drawn will "
00109         "be within a factor of 2 of the value. Asking for fewer than 10 or "
00110         "more than 1000 lines is likely to be ineffective. Unnamed parameters "
00111         "can contain specific x,y,z values of points to start a field line.\n\n"
00112         "Lines are drawn in both directions starting from the plane of the "
00113         "circle, and each half-line stops when it again reaches that plane. "
00114         "Line drawing also stops "
00115         "whenever |B| is less than minField or when it leaves the world. If "
00116         "you are interested in field lines far outside the magnets, you may "
00117         "need to add some object with a large value of x, y, and/or z, in "
00118         "order to expand the world volume. "
00119         "With dl=1 and subdivide=10, the accuracy of their meeting is usually "
00120         "better than 0.1 mm after several tens of meters.\n\n"
00121         "This command does nothing if not in visualization mode. For best "
00122         "results, use the Open Inventor viewer, and give your magnets a "
00123         "transparency of about 0.3 (e.g. color=1,1,1,0.3); if necessary, use "
00124         "the right-button menu to set the DrawStyle/TransparencyType to "
00125         "'sorted object add'. With field lines in 3-d, you will want the "
00126         "ability to zoom, rotate, and move the image interactively.\n\n"
00127         "Setting exit=1 will display the system and the field lines, without "
00128         "any event tracks; exiting the viewer will then exit the program. "
00129         "With exit=0, field lines are drawn only at the end of the first run.");
00130 
00131         t = 0.0*ns;
00132         centerStr = "0,0,0";
00133         radius = 100.0*mm;
00134         nLines = 100;
00135         dl = 10.0*mm;
00136         color="1,1,1";
00137         minField = 0.001*tesla;
00138         maxPoints = 10000;
00139         subdivide = 10;
00140         N = 128;
00141         exit = 0;
00142         square = 0;
00143         Efield = 0;
00144         forever = 0;
00145         visManager = 0; // set in callback(4)
00146         field = 0;      // set in callback(4)
00147         ic = N/2;
00148         dx = 0.0;
00149         scale = ic/4;
00150         rot = 0;        // set in callback(4)
00151         worldHalfHeight = worldHalfWidth = worldHalfLength = 0.0;
00152 }


Member Function Documentation

G4String BLCMDfieldlines::commandName (  )  [inline, virtual]

Implements BLCommand.

00068 { return "fieldlines"; }

int BLCMDfieldlines::command ( BLArgumentVector argv,
BLArgumentMap namedArgs 
) [virtual]

Implements BLCommand.

References argPoints, BLCMDfieldlines(), center, centerStr, dx, Efield, BLCommand::getList(), BLManager::getObject(), BLCommand::handleNamedArgs(), ic, minField, N, BLCommand::print(), BLCommand::printError(), radius, BLManager::registerCallback(), and scale.

00182 {
00183         handleNamedArgs(namedArgs);
00184 
00185         argPoints.clear();
00186         for(unsigned i=0; i<argv.size(); ++i) {
00187                 std::vector<double> list = getList(argv[i],",");
00188                 if(list.size() != 3) {
00189                         printError("Invalid point: %s",argv[i].c_str());
00190                         continue;
00191                 }
00192                 argPoints.push_back(G4ThreeVector(list[0],list[1],list[2]));
00193         }
00194 
00195         if(N < 10 || N > 16383)
00196                 printError("Invalid N: < 10 or > 16383");
00197         ic = N/2;
00198         dx = radius/ic;
00199         scale = ic/4;
00200 
00201         std::vector<double> tmp = getList(centerStr,",");
00202         if(tmp.size() != 3)
00203                 printError("Invald value for center '%s'",centerStr.c_str());
00204         else
00205                 center = G4ThreeVector(tmp[0],tmp[1],tmp[2]);
00206 
00207         if(Efield)
00208                 minField = minField/tesla*(megavolt/meter);
00209 
00210         print("");
00211 
00212         BLManager::getObject()->registerCallback(new BLCMDfieldlines(*this),4);
00213 
00214         return 0;
00215 }

void BLCMDfieldlines::defineNamedArgs (  )  [virtual]

Reimplemented from BLCommand.

References BLCommand::argDouble(), BLCommand::argInt(), BLCommand::argString(), centerStr, color, dl, Efield, exit, forever, maxPoints, minField, N, nLines, radius, square, subdivide, and t.

00218 {
00219         argDouble(t,"t","Time at which field lines are plotted (0 ns).",ns);
00220         argString(centerStr,"center","Center of circle (x,y,z) to start lines (mm, global).");
00221         argDouble(radius,"radius", "Radius of circle to start lines (mm).",mm);
00222         argInt(nLines,"nLines","Approximate number of field lines to plot (100).");
00223         argDouble(dl,"dl","Interval between points plotted (10 mm).",mm);
00224         argString(color,"color","Color of field lines (white=\"1,1,1\").");
00225         argDouble(minField,"minField","Minimum B field (0.001 tesla)",tesla);
00226         argInt(maxPoints,"maxPoints","Max # points plotted in a line (10000).");
00227         argInt(subdivide,"subdivide","# field integration points between plotted points (10).");
00228         argInt(N,"N","# grid points in x and y (128).");
00229         argInt(exit,"exit","Set nonzero to display field lines and exit (0).");
00230         argInt(square,"square","Set nonzero to start from square rather than circle (0).");
00231         argInt(Efield,"Efield","Set nonzero to draw E field (0); minField is in MegaVolts/meter.");
00232         argInt(forever,"forever","Set nonzero to draw lines until maxPoints is reached or |B|<minField, not stopping at the initial plane.");
00233 }

bool BLCMDfieldlines::isInWorld ( G4ThreeVector &  pos  ) 

References worldHalfHeight, worldHalfLength, and worldHalfWidth.

Referenced by generateOneFieldLine().

00236 {
00237         return fabs(pos[0]) <= worldHalfWidth && 
00238                 fabs(pos[1]) <= worldHalfHeight &&
00239                 fabs(pos[2]) <= worldHalfLength;
00240 }

void BLCMDfieldlines::generatePoints (  ) 

References BLAssert, bmag(), distance2, exclude, excludeRadiusSq(), ic, index, N, point(), points, and square.

Referenced by callback().

00396 {
00397 /*      This routine places points for field lines into the circle in the
00398         plane normal to B at center.
00399 
00400         The basic algorithm is to cover the circle with an NxN grid, to
00401         place points in the grid, and then to exclude grid points within
00402         a given radius of the point; the radius depends on the value of B
00403         at the point just placed. The first point is placed at the center,
00404         and successive points are placed at the non-excluded grid point
00405         closest to the center.
00406 */
00407 #define index(i,j) (i*N+j)
00408 #define distance2(i1,j1,i2,j2) ((i1-i2)*(i1-i2) + (j1-j2)*(j1-j2))
00409 #define exclude(I,J,D2)                                                 \
00410         for(int i=0; i<N; ++i) {                                \
00411                 for(int j=0; j<N; ++j) {                        \
00412                         if(distance2(i,j,I,J) <= D2)            \
00413                                 grid[index(i,j)] = 0;           \
00414                 }                                               \
00415         }
00416 
00417         BLAssert(N >= 10 && N <= 16383); // ensure distance2() fits in an int
00418 
00419         unsigned char *grid = new unsigned char[N*N];
00420 
00421         // initialize grid(), excluding points outside radius
00422         int excludeSq = ic*ic;
00423         for(int i=0; i<N; ++i) {
00424                 for(int j=0; j<N; ++j) {
00425                         if(!square && distance2(i,j,ic,ic) > excludeSq)
00426                                 grid[index(i,j)] = 0;
00427                         else
00428                                 grid[index(i,j)] = 1;
00429                 }
00430         }
00431 
00432         // place as many points as will fit, starting with (ic,ic)
00433         int imin=ic, jmin=ic;
00434         do {
00435                 // place this point
00436                 G4ThreeVector p = point(imin,jmin);
00437                 points.push_back(p);
00438                 exclude(imin,jmin,excludeRadiusSq(bmag(i,j)));
00439 
00440                 // find un-excluded point closest to (ic,ic)
00441                 int d2min=N*N;
00442                 imin = -1;
00443                 for(int i=0; i<N; ++i) {
00444                         for(int j=0; j<N; ++j) {
00445                                 if(grid[index(i,j)] == 0) continue;
00446                                 int d2=distance2(i,j,ic,ic);
00447                                 if(d2 < d2min) {
00448                                         d2min = d2;
00449                                         imin = i;
00450                                         jmin = j;
00451                                 }
00452                         }
00453                 }
00454         } while(imin >= 0);
00455 }

void BLCMDfieldlines::generateOneFieldLine ( G4ThreeVector &  point  ) 

References B, BLAssert, color, dl, E, Efield, field, forever, BLGlobalField::getFieldValue(), BLCommand::getVisAttrib(), isInWorld(), lines, maxPoints, minField, subdivide, and t.

Referenced by callback().

00323 {
00324         BLAssert(subdivide > 0);
00325 
00326         double step = dl/subdivide;
00327         G4ThreeVector B, E, norm;
00328         G4ThreeVector pos=point;
00329         if(!isInWorld(pos)) return;
00330         field->getFieldValue(pos,t,B,E);
00331         if(Efield) B = E;
00332         if(B.mag() < minField) return;
00333         // norm is the normal to the plane perpendicular to B at this point.
00334         norm = B.unit();
00335 
00336         G4Polyline line;
00337         line.SetVisAttributes(getVisAttrib(color));
00338 
00339         // half-line on positive side of norm
00340         pos = point;
00341         line.push_back(pos);
00342         for(int n=0; n<maxPoints; ++n) {
00343                 for(int j=0; j<subdivide; ++j) {
00344                         if(!isInWorld(pos)) goto end1;
00345                         if(forever == 0 && (pos-point)*norm < 0.0) break;
00346                         field->getFieldValue(pos,t,B,E);
00347                         if(Efield) B = E;
00348                         if(B.mag() < minField) goto end1;
00349                         pos += step*B.unit();
00350                 }
00351                 line.push_back(pos);
00352                 if(forever == 0 && (pos-point)*norm < 0.0) break;
00353         }
00354 end1:   if(line.size() > 1) lines.push_back(line);
00355         line.clear();
00356 
00357         // half-line on negative side of norm
00358         pos = point;
00359         line.push_back(pos);
00360         for(int n=0; n<maxPoints; ++n) {
00361                 for(int j=0; j<subdivide; ++j) {
00362                         if(!isInWorld(pos)) goto end2;
00363                         if(forever == 0 && (pos-point)*norm > 0.0) break;
00364                         field->getFieldValue(pos,t,B,E);
00365                         if(Efield) B = E;
00366                         if(B.mag() < minField) goto end2;
00367                         pos -= step*B.unit();
00368                 }
00369                 line.push_back(pos);
00370                 if(forever == 0 && (pos-point)*norm > 0.0) break;
00371         }
00372 end2:   if(line.size() > 1) lines.push_back(line);
00373 }

void BLCMDfieldlines::callback ( int  type  )  [virtual]

Reimplemented from BLCallback.

References argPoints, B, BLAssert, bmag(), center, Draw(), E, Efield, exit, field, g4bl_exit(), generateOneFieldLine(), generatePoints(), BLGlobalField::getFieldValue(), BLGroup::getHeight(), BLGroup::getLength(), BLGlobalField::getObject(), BLVisManager::getObject(), BLGroup::getWidth(), BLGroup::getWorld(), ic, lines, minField, nLines, points, radius, rot, scale, t, visManager, worldHalfHeight, worldHalfLength, and worldHalfWidth.

00243 {
00244         // initialize variables that must be delayed.
00245         visManager = BLVisManager::getObject();
00246         if(!visManager) return;
00247         field = BLGlobalField::getObject();
00248         BLGroup *world = BLGroup::getWorld();
00249         worldHalfHeight = world->getHeight()/2.0;
00250         worldHalfWidth = world->getWidth()/2.0;
00251         worldHalfLength = world->getLength()/2.0;
00252 
00253         if(radius > 0.0 && nLines > 0) {
00254                 // get rotation from Z axis to B at center.
00255                 G4ThreeVector B, E, axis(0.0,0.0,1.0);
00256                 field->getFieldValue(center,t,B,E);
00257                 if(Efield) B = E;
00258                 if(B.mag() < minField) return;
00259                 axis = axis.cross(B.unit());
00260                 if(axis.mag() > 1.0e-6)
00261                     rot = new G4RotationMatrix(axis.unit(),acos(B.unit()[2]));
00262                 else
00263                     rot = new G4RotationMatrix();
00264                 G4ThreeVector test = *rot * G4ThreeVector(0.0,0.0,1.0);
00265                 BLAssert((test-B.unit()).mag()<1.0e-6 || (test+B.unit()).mag()<1.0e-6);
00266 
00267                 fflush(stdout);
00268                 fprintf(stderr,"\n");
00269 
00270                 // generate the points from which field lines are drawn
00271                 // loop over scale to get within a factor of 2 of nLines.
00272                 scale = (ic/4)*bmag(ic,ic);
00273                 for(int i=0; i<15; ++i) {
00274                     fprintf(stderr,"fieldlines: trying for ~ %d field lines...",
00275                                                                         nLines);
00276                     points.clear();
00277                     generatePoints();
00278                     int n = points.size();
00279                     fprintf(stderr," got %d\n",n);
00280                     if(n <= 0) return;
00281                     if(n < nLines/2)
00282                         scale = 0.75*scale;
00283                     else if(n > nLines*2)
00284                         scale = 1.2*scale;
00285                     else
00286                         break;
00287                 }
00288         }
00289 
00290         // add argPoints
00291         for(unsigned i=0; i<argPoints.size(); ++i)
00292                 points.push_back(argPoints[i]);
00293 
00294         // generate the field lines.
00295         fprintf(stderr,"fieldlines: generating %d field lines...",
00296                                                 (int)points.size());
00297         lines.clear();
00298         for(unsigned i=0; i<points.size(); ++i) {
00299                 generateOneFieldLine(points[i]);
00300         }
00301         fprintf(stderr," done.\n\n");
00302 
00303         visManager->SetUserAction(this,
00304              G4VisExtent(-DBL_MAX,DBL_MAX,-DBL_MAX,DBL_MAX,-DBL_MAX,DBL_MAX));
00305 
00306         // draw the field lines
00307         Draw();
00308 
00309         if(exit) {
00310                 G4UImanager* UI = G4UImanager::GetUIpointer();
00311                 UI->ApplyCommand("/vis/viewer/update");
00312                 g4bl_exit(0);
00313         }
00314 }

void BLCMDfieldlines::Draw (  ) 

References lines, and visManager.

Referenced by callback().

00317 {
00318         for(unsigned i=0; i<lines.size(); ++i) 
00319                 visManager->Draw(lines[i]);
00320 }

double BLCMDfieldlines::bmag ( int  i,
int  j 
)

References B, E, Efield, field, BLGlobalField::getFieldValue(), point(), and t.

Referenced by callback(), and generatePoints().

00376 {
00377         G4ThreeVector p(point(i,j)),B, E;
00378         field->getFieldValue(p,t,B,E);
00379         if(Efield) B = E;
00380         return B.mag();
00381 }

G4ThreeVector BLCMDfieldlines::point ( int  i,
int  j 
)

References center, dx, ic, and rot.

Referenced by bmag(), and generatePoints().

00384 {
00385         return center + *rot * G4ThreeVector((i-ic)*dx,(j-ic)*dx,0.0);
00386 }

int BLCMDfieldlines::excludeRadiusSq ( double  bmag  ) 

References minField, N, and scale.

Referenced by generatePoints().

00389 {
00390         if(bmag < minField) return N*N;
00391 
00392         return (int)((scale/bmag)*(scale/bmag));
00393 }


Member Data Documentation

G4double BLCMDfieldlines::t [private]

G4String BLCMDfieldlines::centerStr [private]

G4double BLCMDfieldlines::radius [private]

G4int BLCMDfieldlines::nLines [private]

G4double BLCMDfieldlines::dl [private]

G4String BLCMDfieldlines::color [private]

G4double BLCMDfieldlines::minField [private]

G4int BLCMDfieldlines::maxPoints [private]

G4int BLCMDfieldlines::subdivide [private]

G4int BLCMDfieldlines::N [private]

G4int BLCMDfieldlines::exit [private]

G4int BLCMDfieldlines::square [private]

G4int BLCMDfieldlines::Efield [private]

G4int BLCMDfieldlines::forever [private]

G4ThreeVector BLCMDfieldlines::center [private]

Referenced by callback(), command(), and point().

std::vector<G4ThreeVector> BLCMDfieldlines::points [private]

Referenced by callback(), and generatePoints().

std::vector<G4ThreeVector> BLCMDfieldlines::argPoints [private]

Referenced by callback(), and command().

std::vector<G4Polyline> BLCMDfieldlines::lines [private]

Referenced by BLCMDfieldlines(), callback(), and Draw().

int BLCMDfieldlines::ic [private]

double BLCMDfieldlines::dx [private]

Referenced by BLCMDfieldlines(), command(), and point().

double BLCMDfieldlines::scale [private]

G4RotationMatrix* BLCMDfieldlines::rot [private]

Referenced by BLCMDfieldlines(), callback(), and point().


The documentation for this class was generated from the following file:
g4beamline