Opened 8 years ago
Closed 8 years ago
#1033 closed defect (wontfix)
Possible bug in half_cylinder_rotations
| Reported by: | Tristan Croll | Owned by: | Tom Goddard |
|---|---|---|---|
| Priority: | minor | Milestone: | |
| Component: | Core | Version: | |
| Keywords: | Cc: | ||
| Blocked By: | Blocking: | ||
| Notify when closed: | Platform: | all | |
| Project: | ChimeraX |
Description
I call it a "possible bug" since it's only arisen for me since I copied the logic to a separate function (used for a position restraint implementation that avoids using fake atoms and pseudobonds, copied to a header file so I can call it directly from C++) and used it in double precision (code copied below). In ChimeraX's _geometry/cylinderrot.cpp the lines:
if (d == 0)
{ vx = vy = 0 ; vz = 1; }
else
{ vx /= d; vy /= d; vz /= d; }
seem to work just fine - but in double precision I found I had to make the modifications involving ALMOST_ZERO (currently defined as 1e-6) to avoid Numpy throwing up its hands over singular matrices when the bond length is zero (i.e. when the target positions are set to the atom coordinates).
template <typename T>
void bond_cylinder_transform_gl(T xyz0[3], T xyz1[3], T r, T *rot44)
{
T bvec[3];
for (size_t i=0; i<3; i++) {
bvec[i] = xyz1[i]-xyz0[i];
}
T d = l2_norm_3d(bvec);
if (d < ALMOST_ZERO) {
bvec[0]=0; bvec[1]=0; bvec[2]=1;
d = ALMOST_ZERO;
} else {
for (auto &b: bvec)
b/=d;
}
T &c = bvec[2], c1;
if (c <= -1) c1 = 0;
else c1 = 1.0/(1.0+c);
T wx = -bvec[1], wy = bvec[0];
T cx = c1*wx, cy = c1*wy;
T h = d*2;
*rot44++ = r*(cx*wx + c);
*rot44++ = r*cy*wx;
*rot44++ = -r*wy;
*rot44++ = 0;
*rot44++ = r*cx*wy;
*rot44++ = r*(cy*wy + c);
*rot44++ = r*wx;
*rot44++ = 0;
*rot44++ = h*wy;
*rot44++ = -h*wx;
*rot44++ = h*c;
*rot44++ = 0;
*rot44++ = (xyz0[0]+xyz1[0])/2;
*rot44++ = (xyz0[1]+xyz1[1])/2;
*rot44++ = (xyz0[2]+xyz1[2])/2;
*rot44++ = 1;
}
Change History (3)
follow-up: 2 comment:2 by , 8 years ago
Avoiding divide by zero is tricky to do right. I agree my test for equality to zero has problems although I have never seen it cause trouble in that ChimeraX code. Unfortunately your fix has its own problems. For instance if I decide to use units of meters for my molecules then all bond lengths are now smaller than your divide by zero cutoff of 1e-6 and all ChimeraX bonds would be drawn parallel to the z axis just because I switched units. The vectors maintain their full precision scaled down by 1e-10. So your test has introduced an assumption about the magnitudes of the vectors. You may think that is far fetched but I once made an animation zooming from full human brain imaging down to molecular scale and units of meters would be very reasonable. I think the only right solution is to use a serious vector math library normalization routine that has the code to handle loss of precision scenarios. But I would just use your solution if it works for you. But since a double has about 15 decimal digits precision I might lower your cutoff to 1e-10.
comment:3 by , 8 years ago
| Resolution: | → wontfix |
|---|---|
| Status: | assigned → closed |
The resulting error is pretty easy to debug and I have no easy way to reduce the error potential so will ignore this until it becomes a problem.