/* * dynamics.c * xgas: Copyright 1990 Larry Medwin: @(#)dynamics.c 1.5 2/9/90 * Larry Medwin -- Dec. 15, 1989 * fixed: lm 3-24-91 */ #include "xgas.h" static void inertia(); static void collide(); static double hit(); static double hitHole(); /* DYNAMICS */ void dynamics( mol, data ) Molecule *mol; LabData *data; { /* Move molecule */ while( mol->collisionTime <= data->timestepSize) { collide( mol, data ); findNextCollision( mol, data); } inertia( mol, data ); } /* INERTIA() */ static void inertia( mol, data) Molecule *mol; LabData *data; { /* Solve equations of motion */ mol->pos.x = mol->xCoeff[0] += mol->xCoeff[1] * data->timestepSize; mol->pos.y = mol->yCoeff[0] += mol->yCoeff[1] * data->timestepSize; mol->collisionTime -= data->timestepSize; } /* * COLLIDE() * bounce a molecule off a wall with given temperature * recompute its new velocity, * including next collision info. */ static void collide( mol, data) Molecule *mol; LabData *data; { float vMagnitude, hypot; float x, y; float theta, thetaRand; WallType *wallParams; int corner; /* Find out about the wall we're about to hit */ wallParams = &WallParam[ mol->collisionWall->type ]; /* * Are we colliding with a corner? */ if ((corner = whichCorner( mol->collisionPos.x, mol->collisionPos.y, mol->thisBox, data)) != 0) wallParams = &WallParam[ corner ]; /* Reflect the trajectory */ mol->xCoeff[1] *= wallParams->wallReflect.x; mol->yCoeff[1] *= wallParams->wallReflect.y; /* Rotate the trajectory into the canonical orientation */ x = mol->xCoeff[1] * wallParams->toRotate[0][0] + mol->yCoeff[1] * wallParams->toRotate[0][1]; y = mol->xCoeff[1] * wallParams->toRotate[1][0] + mol->yCoeff[1] * wallParams->toRotate[1][1]; /* Find reflection angle theta */ if ( fabs ( x ) > SMALL ) theta = atan ( y / x ); else if ( y > 0.0 ) theta = M_PI_2; else theta = -M_PI_2; /* Randomize angle by the weight "randomBounce" */ if (corner) thetaRand = frand( 0.0, M_PI_2); else thetaRand = frand( -M_PI_2, M_PI_2); theta = (1.0 - data->randomBounce) * theta + data->randomBounce * thetaRand; /* Molecule approaches equilibrium according to weight "equilibrium" */ mol->temperature = (1.0 - data->equilibrium) * mol->temperature + data->equilibrium * data->chamber[mol->thisBox].temperature; /* Find velocity vector magnitude */ vMagnitude = vEquilibrium( mol->temperature); /* ... and components */ x = vMagnitude * cos( theta ); y = vMagnitude * sin( theta ); /* Rotate the trajectory back to its original orientation */ mol->xCoeff[1] = x * wallParams->fromRotate[0][0] + y * wallParams->fromRotate[0][1]; mol->yCoeff[1] = x * wallParams->fromRotate[1][0] + y * wallParams->fromRotate[1][1]; } /* * FIND TIME AND POSITION OF NEXT COLLISION * given the equations of motion for the molecule */ void findNextCollision( mol, data) Molecule *mol; LabData *data; { int i; int box; double deltaT; Coord lastCollision; /* Save position of last collision */ lastCollision.x = mol->collisionPos.x; lastCollision.y = mol->collisionPos.y; box = mol->thisBox; /* Do we go through the hole? (walls[0]) */ if( hitHole( mol, &data->chamber[box].walls[0], data) > 0.0) { /* Move into the other box */ box = 1 - box; } /* * Now check for collisions with the walls * Update collisionPos in hit() */ for( i=1; icollisionWall != &data->chamber[box].walls[i]) && (( deltaT = hit( mol, &data->chamber[box].walls[i])) > 0.0)) { break; } } if( deltaT == -1) { error("In findNextCollision(): couldn't find a wall to hit.", data->time); } /* Correct the equations of motion for the particle */ mol->xCoeff[1] = (mol->collisionPos.x - lastCollision.x) / deltaT; mol->yCoeff[1] = (mol->collisionPos.y - lastCollision.y) / deltaT; mol->xCoeff[0] = lastCollision.x; mol->yCoeff[0] = lastCollision.y; /* Update collision info */ mol->collisionTime = deltaT; mol->collisionWall = &data->chamber[box].walls[i]; mol->thisBox = box; } /* * HIT * Return collision time if the molecule will hit this wall * otherwise -1.0 */ static double hit( mol, wall) Molecule *mol; Wall *wall; { double deltaT; int xPos, yPos; /* Find intersection of trajectory and wall */ /* Horizontal wall */ if( wall->type == TOP || wall->type == BOTTOM) { if( fabs( mol->yCoeff[1]) >= SMALL) { deltaT = (wall->end[0].y-mol->collisionPos.y) / mol->yCoeff[1]; /* Are we headed in that direction? */ if( deltaT < 0.0) return -1.0; xPos = mol->collisionPos.x + mol->xCoeff[1] * deltaT; /* Hits wall between endpoints */ if( xPos >= wall->end[0].x && xPos <= wall->end[1].x) { mol->collisionPos.x = xPos; mol->collisionPos.y = wall->end[0].y; return deltaT; } else return -1.0; } else return -1.0; } /* Vertical wall */ else if ( wall->type == LEFT || wall->type == RIGHT) { if( fabs( mol->xCoeff[1]) >= SMALL) { deltaT = (wall->end[0].x - mol->collisionPos.x) / mol->xCoeff[1]; /* Are we headed in that direction? */ if( deltaT < 0.0) return -1.0; yPos = mol->collisionPos.y + mol->yCoeff[1] * deltaT; /* Hits wall between endpoints */ if( yPos >= wall->end[0].y && yPos <= wall->end[1].y) { mol->collisionPos.x = wall->end[0].x; mol->collisionPos.y = yPos; return deltaT; } else return -1.0; } else return -1.0; } else { error(" In hit, illegal wall type.", 0); return -1.0; } } /* * HITHOLE * Return collision time if the molecule will go through hole * otherwise -1.0 */ static double hitHole( mol, wall, data) Molecule *mol; Wall *wall; LabData *data; { double deltaT; int xPos, yPos; /* Find intersection of trajectory and hole */ /* OK to divide? */ if( fabs( mol->xCoeff[1]) < SMALL) return -1.0; deltaT = (wall->end[0].x - mol->collisionPos.x) / mol->xCoeff[1]; /* Are we headed in that direction? */ /* ... or already on wall or corner? use <=, not < lm 4/4/91 */ if( deltaT <= 0.0) return -1.0; /* FInd intersection with barrier wall */ yPos = mol->collisionPos.y + mol->yCoeff[1] * deltaT; /* Does it go through hole between endpoints? */ if( !( yPos > wall->end[0].y && yPos < wall->end[1].y)) return -1.0; /* * Check that x-intersection with horizontal wall will not * be truncated to corner position. This happens once * every 10^7 collisions. */ /* This isn't a problem for molecules moving in -x direction */ if( mol->xCoeff[1] < 0.0) return deltaT; /* OK to divide? */ if( fabs( mol->yCoeff[1]) < SMALL) return -1.0; /* Moving in +y or -y direction? */ if( mol->yCoeff[1] > 0.0) deltaT = (data->heightMM - mol->collisionPos.y) / mol->yCoeff[1]; else deltaT = (0 - mol->collisionPos.y) / mol->yCoeff[1]; /* Where do we hit the horizontal wall? */ xPos = mol->collisionPos.x + mol->xCoeff[1] * deltaT; /* * If xPos truncated so that it lies at the x-position of the corner, * then the molecule really doesn't go through the hole. */ if( xPos == data->chamber[0].walls[0].end[0].x) return -1.0; /* It went through! */ return deltaT; }