void DContact::ResolveCollisions(const float2& Ncoll, float t, float fCoF, float fCoR, const float2& C0, const float2& P0, float2& V0, float& w0, float m0, float i0, const float2& C1, const float2& P1, float2& V1, float& w1, float m1, float i1) { // pre-computations float tcoll = t > 0.0f ? t : 0.0f; float2 Q0 = P0 + V0 * tcoll; float2 Q1 = P1 + V1 * tcoll; float2 R0 = C0 - Q0; float2 R1 = C1 - Q1; float2 T0(-R0.y, R0.x); float2 T1(-R1.y, R1.x); float2 VP0 = V0 - T0 * w0; float2 VP1 = V1 - T1 * w1; // impact velocity float2 Vcoll = VP0 - VP1; float vn = Vcoll.dot(Ncoll); float2 Vn = Ncoll * vn; float2 Vt = Vcoll - Vn; if(vn > 0.0f) { return; } float vt = Vt.magnitude(); Vt = Vt.normalize(); // compute impulse (friction and restitution) float2 J, Jt(0.0f, 0.0f), Jn(0.0f, 0.0f); float t0 = (R0 ^ Ncoll) * (R0 ^ Ncoll) * i0; float t1 = (R1 ^ Ncoll) * (R1 ^ Ncoll) * i1; float m = m0 + m1; float denom = m + t0 + t1; float jn = vn / denom; Jn = Ncoll * (-(1.0f + fCoR) * jn); // restitution Jt = Vt.normalize() * (fCoF * jn); // friction J = Jn + Jt; // changes in momentum float2 dV0 = J * m0; float2 dV1 = -J * m1; float dw0 =-(R0 ^ J) * i0; float dw1 = (R1 ^ J) * i1; if(m0 > 0.0f) { V0 += dV0; w0 += dw0; }; // apply changes in momentum if(m1 > 0.0f) { V1 += dV1; w1 += dw1; }; // apply changes in momentum // Check for static frcition if (vn < 0.0f && fCoF > 0.0f) { float cone = -vt / vn; if (cone < fCoF) { float2 Nfriction = -Vt.normalize(); float fCoS = cmat.coStaticFriction; ResolveCollisions(Nfriction, 0.0f, 0.0f, fCoS, C0, P0, V0, w0, m0, i0, C1, P1, V1, w1, m1, i1); } } };
//======================================================================== //======================================================================== // // NAME: complex<double> bessel_1_complex(int n, complex<double> arg) // // DESC: Calculates the Bessel function of the first kind (Jn) for // complex arguments. // // INPUT: // int n:: Order of Bessel function // complex<double> arg: Bessel function argument // // OUTPUT: // Jn:: Bessel function of the first kind of order n // // NOTES: 1) The Bessel function of the first kind is defined as: // Jn(x) = ((x/2.0)^n)*sum{m=0, m=inf}[(((-x^2)/4.0)^m)/(m!*(n+m)!) // // 2) J-n = ((-1)^n)*Jn // // 3) The infinite series representing the Bessel function // converges for all arguments given that enough terms are taken: // k >> |arg| // //======================================================================== //======================================================================== complex<double> bessel_1_complex(int n, complex<double> arg) { complex<double> Jn(0.0, 0.0); complex<double> Jn_series(0.0, 0.0); complex<double> Jn_seriesm1(0.0, 0.0); double tolerance = 100.0*depsilon(); // Make sure that we calculate the positive order Bessel function int m = abs(n); // !!! I don't know if this will be large enough int k_max_r, k_max_im; k_max_r = static_cast<int>(real(arg)); k_max_im = static_cast<int>(imag(arg)); /* int k_max = 10*imax(k_max_r, k_max_im); for(int k = 0; k <= k_max; k++) { Jn_series = Jn_series + pow((0.0 - arg*arg/4.0), k)/(dfactorial(k)*dfactorial(k+m)); } */ // !!! my concern with this do loop is that if a certain term contributes 0 then the // loop may inappropriately exit int k_max2 = static_cast<int>(2.0*static_cast<double>(imax(k_max_r, k_max_im))) + 1; int k = 0; do { Jn_seriesm1 = Jn_series; Jn_series = Jn_series + pow((0.0 - arg*arg/4.0), k)/(dfactorial(k)*dfactorial(k+m)); k = k + 1; } while ((sqrt(real(Jn_series*conj(Jn_series) - Jn_seriesm1*conj(Jn_seriesm1))) > tolerance) || (k < k_max2)); Jn = pow((arg/2.0), m)*Jn_series; // NOW WE WILL MAKE USE OF THE BESSEL FUNCTION RELATION FOR NEGATIVE n: // J(n-1) = (-1)^n*Jn if(n < 0) { Jn = pow((0.0 - 1.0), m)*Jn; } return Jn; }
//////////////////////////////////////////////////////////////// // ResolveCollision //////////////////////////////////////////////////////////////// // calculates the change in angular and linear velocity of two // colliding objects //////////////////////////////////////////////////////////////// // parameters : // ------------ // Ncoll : normal of collision // t : time of collision, (if negative, it's a penetration depth) // fCoF : coefficient of friction // fCoR : coefficient of restitution // C0 : point of contact on object 0 // P0 : centre of gravity (position) of object 0 // V0 : linear Velocity of object 0 // w0 : angular velocity of object 0 // m0 : inverse mass of object 0 // i0 : inverse inertia of object 0 // C1 : point of contact on object 1 // P1 : centre of gravity (position) of object 1 // V1 : linear Velocity of object 1 // w1 : angular velocity of object 1 // m1 : inverse mass of object 1 // i1 : inverse inertia of object 1 // // return values : V0, w0, V1, w1 will change upon a collision // ------------- /////////////////////////////////////////////////////////////// void ResolveCollision(const glm::vec2& Ncoll, float t, float fCoF, float fCoR, const glm::vec2& C0, const glm::vec2& P0, glm::vec2& V0, float& w0, float m0, float i0, const glm::vec2& C1, const glm::vec2& P1, glm::vec2& V1, float& w1, float m1, float i1) { //------------------------------------------------------------------------------------------------------ // pre-computations //------------------------------------------------------------------------------------------------------ float tcoll = (t > 0.0f)? t : 0.0f; glm::vec2 Q0 = P0 + V0 * tcoll; glm::vec2 Q1 = P1 + V1 * tcoll; glm::vec2 R0 = C0 - Q0; glm::vec2 R1 = C1 - Q1; glm::vec2 T0 = glm::vec2(-R0.y, R0.x); glm::vec2 T1 = glm::vec2(-R1.y, R1.x); glm::vec2 VP0 = V0 - T0 * w0; // point velocity (SIGN IS WRONG) glm::vec2 VP1 = V1 - T1 * w1; // point velocity (SIGN IS WRONG) //------------------------------------------------------------------------------------------------------ // impact velocity //------------------------------------------------------------------------------------------------------ glm::vec2 Vcoll = VP0 - VP1; float vn = glm::dot(Vcoll, Ncoll); glm::vec2 Vn = vn * Ncoll; glm::vec2 Vt = Vcoll - Vn; // separation if (vn > 0.0f) return; float vt = glm::length(Vt); //------------------------------------------------------------------------------------------------------ // compute impulse (frction and restitution). // ------------------------------------------ // // -(1+Cor)(Vel.norm) // j = ------------------------------------------------------------ // [1/Ma + 1/Mb] + [Ia' * (ra x norm)²] + [Ib' * (rb x norm)²] //------------------------------------------------------------------------------------------------------ glm::vec2 J; glm::vec2 Jt(0.0f, 0.0f); glm::vec2 Jn(0.0f, 0.0f); float t0 = cross(R0, Ncoll) * cross(R0, Ncoll) * i0; float t1 = cross(R1, Ncoll) * cross(R1, Ncoll) * i1; float m = m0 + m1; float denom = m + t0 + t1; float jn = vn / denom; Jn = (-(1.0f + fCoR) * jn) * Ncoll; if (dbg_UseFriction) { Jt = (fCoF * jn) * glm::normalize(Vt); } J = Jn + Jt; //------------------------------------------------------------------------------------------------------ // changes in momentum //------------------------------------------------------------------------------------------------------ glm::vec2 dV0 = J * m0; glm::vec2 dV1 =-J * m1; float dw0 =-cross(R0, J) * i0; // (SIGN IS WRONG) float dw1 = cross(R1, J) * i1; // (SIGN IS WRONG) //------------------------------------------------------------------------------------------------------ // apply changes in momentum //------------------------------------------------------------------------------------------------------ if (m0 > 0.0f) V0 += dV0; if (m1 > 0.0f) V1 += dV1; if (m0 > 0.0f) w0 += dw0; if (m1 > 0.0f) w1 += dw1; //------------------------------------------------------------------------------------------------------ // Check for static frcition //------------------------------------------------------------------------------------------------------ if (vn < 0.0f && fCoF > 0.0f) { float cone = -vt / vn; if (cone < fCoF) { // treat static friciton as a collision at the contact point glm::vec2 Nfriction = glm::normalize(-Vt); float fCoS = GetStaticFriction; ResolveCollision(Nfriction, 0.0f, 0.0f, fCoS, C0, P0, V0, w0, m0, i0, C1, P1, V1, w1, m1, i1); } } }
/** * @return \e J<sub>n</sub> the dynamical form factors of the ellipsoid. * * If \e n = 2 (the default), this is the value of <i>J</i><sub>2</sub> * used in the constructor. Otherwise it is the zonal coefficient of the * Legendre harmonic sum of the normal gravitational potential. Note that * \e J<sub>n</sub> = 0 if \e n is odd. In most gravity applications, * fully normalized Legendre functions are used and the corresponding * coefficient is <i>C</i><sub><i>n</i>0</sub> = −\e J<sub>n</sub> / * sqrt(2 \e n + 1). **********************************************************************/ Math::real DynamicalFormFactor(int n = 2) const throw() { return Init() ? ( n == 2 ? _J2 : Jn(n)) : Math::NaN<real>(); }
int main() { typedef viennagrid::line_1d_mesh MeshType; typedef viennashe::device<MeshType> DeviceType; typedef viennagrid::result_of::const_cell_range<MeshType>::type CellContainer; std::cout << viennashe::preamble() << std::endl; std::cout << "* main(): Initializing device..." << std::endl; DeviceType device; // // Generate device geometry using built-in device generator // { viennashe::util::device_generation_config generator_params; generator_params.add_segment(0.0, 1e-6, 51); //start at x=0, length 1e-6, 51 points device.generate_mesh(generator_params); } // // Set up and initialize device // init_device(device, 0.1); CellContainer cells(device.mesh()); // // Use a drift-diffusion simulation for obtaining an initial guess of the potential: // std::cout << "* main(): Creating DD simulator..." << std::endl; viennashe::config dd_cfg; dd_cfg.linear_solver().set(viennashe::solvers::linear_solver_ids::dense_linear_solver); dd_cfg.nonlinear_solver().max_iters(50); dd_cfg.nonlinear_solver().damping(0.5); //dd_cfg.nonlinear_solver().set(viennashe::solvers::nonlinear_solver_ids::newton_nonlinear_solver); //uncomment this to use Newton (might require stronger damping) viennashe::simulator<DeviceType> dd_simulator(device, dd_cfg); std::cout << "* main(): Launching simulator..." << std::endl; dd_simulator.run(); // // A single SHE postprocessing step (fixed field) // std::cout << "* main(): Setting up SHE..." << std::endl; viennashe::config config; config.set_electron_equation(viennashe::EQUATION_SHE); config.with_electrons(true); config.with_holes(false); config.set_hole_equation(viennashe::EQUATION_CONTINUITY); config.nonlinear_solver().max_iters(10); config.nonlinear_solver().damping(0.3); config.max_expansion_order(1); config.energy_spacing(0.0155 * viennashe::physics::constants::q); config.min_kinetic_energy_range(1.0 * viennashe::physics::constants::q); // configure scattering mechanisms. We use phonon scattering only for now. config.scattering().acoustic_phonon().enabled(true); config.scattering().optical_phonon().enabled(true); config.scattering().ionized_impurity().enabled(false); config.scattering().impact_ionization().enabled(false); config.scattering().electron_electron(false); //config.dispersion_relation(viennashe::she::dispersion_relation_ids::ext_vecchi_dispersion); //uncomment this to use the extended Vecchi model std::cout << "* main(): Computing SHE (electrons only) without ionized impurity and Modena model ..." << std::endl; viennashe::simulator<DeviceType> she_simulator(device, config); she_simulator.set_initial_guess(viennashe::quantity::potential(), dd_simulator.potential()); she_simulator.set_initial_guess(viennashe::quantity::electron_density(), dd_simulator.electron_density()); she_simulator.set_initial_guess(viennashe::quantity::hole_density(), dd_simulator.hole_density()); she_simulator.run(); std::cout << "* main(): Writing SHE result..." << std::endl; viennashe::io::gnuplot_edf_writer edfwriter; double n_mid_without = 0; double Jn_mid_without = 0; { viennashe::io::she_vtk_writer<DeviceType>()(device, she_simulator.config(), she_simulator.quantities().electron_distribution_function(), "simple_impurity_scattering_edf1"); edfwriter(device, viennashe::util::any_filter(), she_simulator.edf(viennashe::ELECTRON_TYPE_ID), "simple_impurity_scattering_edf1.dat"); typedef viennashe::simulator<DeviceType>::she_quantity_type she_quan_type; viennashe::she::current_density_wrapper<DeviceType, she_quan_type> Jn(device, she_simulator.config(), she_simulator.quantities().electron_distribution_function()); viennashe::she::carrier_density_wrapper<she_quan_type> n( she_simulator.config(), she_simulator.quantities().electron_distribution_function()); viennashe::io::write_cell_quantity_for_gnuplot(Jn, device, "simple_impurity_scattering_Jn1.dat"); n_mid_without = n(cells[25]); Jn_mid_without = Jn(cells[25])[0]; } // #################################################################################################################################### config.scattering().ionized_impurity().enabled(true); // enable ionized impurity scattering std::cout << "* main(): Computing SHE (electrons only) WITH ionized impurity and Modena model ..." << std::endl; viennashe::simulator<DeviceType> she_simulator_with(device, config); she_simulator_with.set_initial_guess(viennashe::quantity::potential(), dd_simulator.potential()); she_simulator_with.set_initial_guess(viennashe::quantity::electron_density(), dd_simulator.electron_density()); she_simulator_with.set_initial_guess(viennashe::quantity::hole_density(), dd_simulator.hole_density()); she_simulator_with.run(); std::cout << "* main(): Writing SHE result..." << std::endl; viennashe::io::she_vtk_writer<DeviceType>()(device, she_simulator_with.config(), she_simulator_with.quantities().electron_distribution_function(), "simple_impurity_scattering_edf2"); //viennashe::io::gnuplot_edf_writer edfwriter; edfwriter(device, viennashe::util::any_filter(), she_simulator_with.edf(viennashe::ELECTRON_TYPE_ID), "simple_impurity_scattering_edf2.dat"); typedef viennashe::simulator<DeviceType>::she_quantity_type she_quan_type; viennashe::she::current_density_wrapper<DeviceType, she_quan_type> Jn(device, config, she_simulator_with.quantities().electron_distribution_function()); viennashe::she::carrier_density_wrapper<she_quan_type> n( config, she_simulator_with.quantities().electron_distribution_function()); viennashe::io::write_cell_quantity_for_gnuplot(Jn, device, "simple_impurity_scattering_Jn2.dat"); double n_mid_with = n(cells[25]); double Jn_mid_with = Jn(cells[25])[0]; if(!viennashe::testing::fuzzy_equal(n_mid_without, n_mid_with)) { std::cerr << "ERROR: Ionized impurity scattering should NOT change the electron density in a resistor!" << std::endl; std::cerr << " The densities are not equal." << std::endl; std::cerr << n_mid_without << " != " << n_mid_with << std::endl; return EXIT_FAILURE; } if(viennashe::testing::fuzzy_equal(Jn_mid_without, Jn_mid_with, 1e-5)) { std::cerr << "ERROR: Ionized impurity scattering should change the electron CURRENT density in a resistor!" << std::endl; std::cerr << " It failed to do so." << std::endl; std::cerr << Jn_mid_without << " == " << Jn_mid_with << std::endl; return EXIT_FAILURE; } else { std::cerr << "BUT: This is ok!" << std::endl; } if(Jn_mid_without < Jn_mid_with) { std::cerr << "ERROR: Ionized impurity scattering should DECREASE the electron CURRENT density in a resistor!" << std::endl; std::cerr << " It failed to do so." << std::endl; return EXIT_FAILURE; } std::cout << std::endl; std::cout << "*********************************************************" << std::endl; std::cout << "* ViennaSHE finished successfully *" << std::endl; std::cout << "*********************************************************" << std::endl; return EXIT_SUCCESS; }
void Contact::ResolveCollision() { if (!m_pxBodies[0] || !m_pxBodies[1]) return; //------------------------------------------------------------------------------------------------------ // parameters //------------------------------------------------------------------------------------------------------ Point2f C0 = m_xContacts[0]; Point2f C1 = m_xContacts[1]; Point2f Ncoll = C1 - C0; // assert(Ncoll.x != 0 || Ncoll.y != 0); Ncoll.Normalize(); float m0 = m_pxBodies[0]->getInvMass(); float m1 = m_pxBodies[1]->getInvMass(); float i0 = m_pxBodies[0]->getInvInertia(); float i1 = m_pxBodies[1]->getInvInertia(); const Point2f& P0 = m_pxBodies[0]->getPosition(); const Point2f& P1 = m_pxBodies[1]->getPosition(); const Point2f& V0 = m_pxBodies[0]->getVelocity(); const Point2f& V1 = m_pxBodies[1]->getVelocity(); float w0 = m_pxBodies[0]->getAngVelocity(); float w1 = m_pxBodies[1]->getAngVelocity(); //------------------------------------------------------------------------------------------------------ // pre-computations //------------------------------------------------------------------------------------------------------ Point2f R0 = C0 - P0; Point2f R1 = C1 - P1; Point2f T0 = Point2f(-R0.y, R0.x); Point2f T1 = Point2f(-R1.y, R1.x); Point2f VP0 = V0 + T0 * w0; // point velocity Point2f VP1 = V1 + T1 * w1; // point velocity //------------------------------------------------------------------------------------------------------ // impact velocity //------------------------------------------------------------------------------------------------------ Point2f Vcoll = VP0 - VP1; float vn = Vcoll * Ncoll; Point2f Vn = Ncoll * vn; Point2f Vt = Vcoll - Vn; if (vn > 0.0f) // separation return; if (Vt * Vt < 0.0001f) Vt = Point2f(0.0f, 0.0f); // float vt = Vt.Length(); Vt.Normalize(); //------------------------------------------------------------------------------------------------------ // compute impulse (frction and restitution). // ------------------------------------------ // // -(1+Cor)(Vel.norm) // j = ------------------------------------------------------------ // [1/Ma + 1/Mb] + [Ia' * (ra x norm)²] + [Ib' * (rb x norm)²] //------------------------------------------------------------------------------------------------------ Point2f J; Point2f Jt(0.0f, 0.0f); Point2f Jn(0.0f, 0.0f); float fCoR = s_xContactMaterial.GetRestitution(); float fCoF = s_xContactMaterial.GetFriction(); float t0 = (R0 ^ Ncoll) * (R0 ^ Ncoll) * i0; float t1 = (R1 ^ Ncoll) * (R1 ^ Ncoll) * i1; float m = m0 + m1; float denom = m + t0 + t1; float jn = vn / denom; Jn = Ncoll * (-(1.0f + fCoR) * jn); //if (dbg_UseFriction) Jt = Vt * (fCoF * jn); J = Jn + Jt; //------------------------------------------------------------------------------------------------------ // changes in momentum //------------------------------------------------------------------------------------------------------ Point2f dV0 = J * m0; Point2f dV1 =-J * m1; float dw0 = (R0 ^ J) * i0; float dw1 =-(R1 ^ J) * i1; //------------------------------------------------------------------------------------------------------ // apply changes in momentum //------------------------------------------------------------------------------------------------------ if (!m_pxBodies[0]->isStaticBody()) { if (m0 > 0.0f) { m_pxBodies[0]->setVelocity(V0 + dV0); } if (m0 > 0.0f) { m_pxBodies[0]->setAngVelocity(w0 + dw0); } } if (!m_pxBodies[1]->isStaticBody()) { if (m1 > 0.0f) { m_pxBodies[1]->setVelocity(V1 + dV1); } if (m1 > 0.0f) { m_pxBodies[1]->setAngVelocity(w1 + dw1); } } // Render(); return; /* //------------------------------------------------------------------------------------------------------ // Check for static frcition //------------------------------------------------------------------------------------------------------ float fRestingContactVelocity = 1.0f; if (-vn < fRestingContactVelocity) { if (vt < fRestingContactVelocity * fCoF) { //------------------------------------------------------------------------------------------------------ // Cancel tangential velocity on the two bodies, so they stick //------------------------------------------------------------------------------------------------------ Point2f dV = V1 - V0; dV -= Ncoll * (dV * Ncoll); if (m0 > 0.0f) V0 += dV * (m0 / m + 0.01f); if (m1 > 0.0f) V1 -= dV * (m1 / m + 0.01f); } } */ }