/// <summary> /// Calculate the new particle position /// </summary> /// <param name="dt"></param> /// <summary> /// Calculate the new particle position /// </summary> /// <param name="dt"></param> protected override Vector CalculateParticlePosition(double dt) { Vector l_Position = GetPosition(1); Aux.TestArithmeticException(l_Position, "particle position"); return(l_Position); }
/// <summary> /// Calculate the new translational velocity of the particle using a Crank Nicolson scheme. /// </summary> /// <param name="dt">Timestep</param> protected override Vector CalculateTranslationalVelocity(double dt) { Vector l_TranslationalVelocity = new Vector(SpatialDim); Aux.TestArithmeticException(l_TranslationalVelocity, "particle translational velocity"); return(l_TranslationalVelocity); }
/// <summary> /// Calculate the new translational velocity of the particle /// </summary> /// <param name="dt">Timestep</param> protected override Vector CalculateTranslationalVelocity(double dt) { Vector l_TranslationalVelocity = GetTranslationalVelocity(1) + GetTranslationalAcceleration(0) * dt; Aux.TestArithmeticException(l_TranslationalVelocity, "particle translational velocity"); return(l_TranslationalVelocity); }
/// <summary> /// Calculate the new angular velocity of the particle using explicit Euler scheme. /// </summary> /// <param name="dt">Timestep</param> /// <param name="collisionTimestep">The time consumed during the collision procedure</param> protected override double CalculateAngularVelocity(double dt) { double l_RotationalVelocity = GetRotationalVelocity(1); Aux.TestArithmeticException(l_RotationalVelocity, "particle rotational velocity"); return(l_RotationalVelocity); }
/// <summary> /// Calculate the new angular velocity of the particle using explicit Euler scheme. /// </summary> /// <param name="dt">Timestep</param> /// <param name="collisionTimestep">The time consumed during the collision procedure</param> protected override double CalculateParticleAngle(double dt) { double angle = GetAngle(1); Aux.TestArithmeticException(angle, "particle rotational velocity"); return(angle); }
/// <summary> /// Returns the support point of the particle in the direction specified by a vector. /// </summary> /// <param name="vector"> /// A vector. /// </param> override public Vector GetSupportPoint(Vector supportVector, int SubParticleID) { Aux.TestArithmeticException(supportVector, "vector in calc of support point"); if (supportVector.L2Norm() == 0) { throw new ArithmeticException("The given vector has no length"); } Vector supportPoint = new Vector(supportVector); double angle = Motion.GetAngle(0); Vector position = new Vector(Motion.GetPosition(0)); Vector rotVector = new Vector(supportVector); rotVector[0] = supportVector[0] * Math.Cos(angle) - supportVector[1] * Math.Sin(angle); rotVector[1] = supportVector[0] * Math.Sin(angle) + supportVector[1] * Math.Cos(angle); Vector length = new Vector(position); length[0] = m_Length * Math.Cos(angle) - m_Thickness * Math.Sin(angle); length[1] = m_Length * Math.Sin(angle) + m_Thickness * Math.Cos(angle); for (int d = 0; d < position.Dim; d++) { supportPoint[d] = Math.Sign(rotVector[d]) * length[d] + position[d]; } return(supportPoint); }
/// <summary> /// Calculate the new particle angle after a collision /// </summary> /// <param name="dt"></param> /// <param name="collisionTimestep">The time consumed during the collision procedure</param> protected override double CalculateParticleAngle(double dt, double collisionTimestep) { double l_Angle = GetAngle(1); Aux.TestArithmeticException(l_Angle, "particle angle"); return(l_Angle); }
/// <summary> /// Calculate the new angular velocity of the particle using explicit Euler scheme. /// </summary> /// <param name="dt">Timestep</param> /// <param name="collisionTimestep">The time consumed during the collision procedure</param> protected override double CalculateAngularVelocity(double dt, double collisionTimestep) { double l_RotationalVelocity = 0; Aux.TestArithmeticException(l_RotationalVelocity, "particle rotational velocity"); return(l_RotationalVelocity); }
/// <summary> /// Calculate the new acceleration (translational and rotational) /// </summary> /// <param name="dt"></param> protected override double CalculateRotationalAcceleration(double dt) { double l_Acceleration = 0; Aux.TestArithmeticException(l_Acceleration, "particle rotational acceleration"); return(l_Acceleration); }
/// <summary> /// Calculate the new translational velocity of the particle using a Crank Nicolson scheme. /// </summary> /// <param name="dt">Timestep</param> protected override Vector CalculateParticlePosition(double dt) { Vector position = GetPosition(1); Aux.TestArithmeticException(position, "particle translational velocity"); return(position); }
/// <summary> /// Constructor for the trap used in the masters thesis if E. Deriabina (2019) /// </summary> /// <param name="motionInit"> /// Initializes the motion parameters of the particle (which model to use, whether it is a dry simulation etc.) /// </param> /// <param name="width"> /// The main lengthscale. /// </param> /// <param name="startPos"> /// The initial position. /// </param> /// <param name="startAngl"> /// The inital anlge. /// </param> /// <param name="activeStress"> /// The active stress excerted on the fluid by the particle. Zero for passive particles. /// </param> /// <param name="startTransVelocity"> /// The inital translational velocity. /// </param> /// <param name="startRotVelocity"> /// The inital rotational velocity. /// </param> public Particle_TrapRight(InitializeMotion motionInit, double width, double[] startPos = null, double startAngl = 0, double activeStress = 0, double[] startTransVelocity = null, double startRotVelocity = 0) : base(motionInit, startPos, startAngl, activeStress, startTransVelocity, startRotVelocity) { m_Length = width; Aux.TestArithmeticException(width, "Particle width"); Motion.SetParticleMaxLengthscale(width); Motion.SetParticleArea(Area); Motion.SetParticleMomentOfInertia(MomentOfInertia); }
/// <summary> /// Constructor for a bean. /// </summary> /// <param name="motionInit"> /// Initializes the motion parameters of the particle (which model to use, whether it is a dry simulation etc.) /// </param> /// <param name="radius"> /// The main lengthscale of the bean. /// </param> /// <param name="startPos"> /// The initial position. /// </param> /// <param name="startAngl"> /// The inital anlge. /// </param> /// <param name="activeStress"> /// The active stress excerted on the fluid by the particle. Zero for passive particles. /// </param> /// <param name="startTransVelocity"> /// The inital translational velocity. /// </param> /// <param name="startRotVelocity"> /// The inital rotational velocity. /// </param> public Particle_Bean(InitializeMotion motionInit, double radius, double[] startPos = null, double startAngl = 0, double activeStress = 0, double[] startTransVelocity = null, double startRotVelocity = 0) : base(motionInit, startPos, startAngl, activeStress, startTransVelocity, startRotVelocity) { m_Radius = radius; Aux.TestArithmeticException(radius, "Particle radius"); Motion.SetParticleMaxLengthscale(radius); Motion.SetParticleArea(Area); Motion.SetParticleMomentOfInertia(MomentOfInertia); }
/// <summary> /// Update Forces and Torque acting from fluid onto the particle /// </summary> /// <param name="U"></param> /// <param name="P"></param> /// <param name="levelSetTracker"></param> /// <param name="fluidViscosity"></param> /// <param name="cutCells"></param> /// <param name="dt"></param> public override double CalculateHydrodynamicTorque(ParticleHydrodynamicsIntegration hydrodynamicsIntegration, CellMask cutCells, double dt) { double tempTorque = hydrodynamicsIntegration.Torque(GetPosition(0), cutCells); Aux.TestArithmeticException(tempTorque, "temporal torque during calculation of hydrodynamics"); TorqueMPISum(ref tempTorque); TorqueAddedDamping(ref tempTorque, dt); return(tempTorque); }
/// <summary> /// Calculate the new translational velocity of the particle using a Crank Nicolson scheme. /// </summary> /// <param name="dt">Timestep</param> protected override double[] CalculateTranslationalVelocity(double dt, double collisionTimestep) { double[] l_TranslationalVelocity = new double[m_Dim]; for (int d = 0; d < m_Dim; d++) { l_TranslationalVelocity[d] = GetTranslationalVelocity(1)[d] + GetTranslationalAcceleration(0)[d] * (dt - collisionTimestep); } Aux.TestArithmeticException(l_TranslationalVelocity, "particle translational velocity"); return(l_TranslationalVelocity); }
/// <summary> /// Calculate the new translational velocity of the particle using a Crank Nicolson scheme. /// </summary> /// <param name="dt">Timestep</param> protected override double[] CalculateTranslationalVelocity(double dt) { double[] l_TranslationalVelocity = new double[m_Dim]; for (int d = 0; d < m_Dim; d++) { l_TranslationalVelocity[d] = 0; } Aux.TestArithmeticException(l_TranslationalVelocity, "particle translational velocity"); return(l_TranslationalVelocity); }
/// <summary> /// Update Forces and Torque acting from fluid onto the particle /// </summary> /// <param name="hydrodynamicsIntegration"></param> /// <param name="fluidDensity"></param> public override Vector CalculateHydrodynamicForces(ParticleHydrodynamicsIntegration hydrodynamicsIntegration, double fluidDensity, CellMask cutCells, double dt) { Vector tempForces = new Vector(hydrodynamicsIntegration.Forces(out List <double[]>[] stressToPrintOut, cutCells)); currentStress = TransformStressToPrint(stressToPrintOut); Aux.TestArithmeticException(tempForces, "temporal forces during calculation of hydrodynamics"); tempForces = ForcesMPISum(tempForces); tempForces = CalculateGravitationalForces(fluidDensity, tempForces); return(tempForces); }
/// <summary> /// Constructor for a hippopede. /// </summary> /// <param name="motionInit"> /// Initializes the motion parameters of the particle (which model to use, whether it is a dry simulation etc.) /// </param> /// <param name="length"> /// The length of the horizontal halfaxis. /// </param> /// <param name="thickness"> /// The length of the vertical halfaxis. /// </param> /// <param name="startPos"> /// The initial position. /// </param> /// <param name="startAngl"> /// The inital anlge. /// </param> /// <param name="activeStress"> /// The active stress excerted on the fluid by the particle. Zero for passive particles. /// </param> /// <param name="startTransVelocity"> /// The inital translational velocity. /// </param> /// <param name="startRotVelocity"> /// The inital rotational velocity. /// </param> public Particle_Hippopede(InitializeMotion motionInit, double length, double thickness, double[] startPos = null, double startAngl = 0, double activeStress = 0, double[] startTransVelocity = null, double startRotVelocity = 0) : base(motionInit, startPos, activeStress, startAngl, startTransVelocity, startRotVelocity) { m_Length = length; m_Thickness = thickness; Aux.TestArithmeticException(length, "Particle length"); Aux.TestArithmeticException(thickness, "Particle thickness"); Motion.SetParticleMaxLengthscale(GetLengthScales().Max()); Motion.SetParticleArea(Area); Motion.SetParticleMomentOfInertia(MomentOfInertia); }
/// <summary> /// Calculate the new particle position /// </summary> /// <param name="dt"></param> protected override double[] CalculateParticlePosition(double dt, double collisionTimestep) { double[] l_Position = new double[m_Dim]; for (int d = 0; d < m_Dim; d++) { l_Position[d] = GetPosition(1)[d]; } Aux.TestArithmeticException(l_Position, "particle position"); return(l_Position); }
/// <summary> /// Constructor for an ellipsoid. /// </summary> /// <param name="motionInit"> /// Initializes the motion parameters of the particle (which model to use, whether it is a dry simulation etc.) /// </param> /// <param name="length"> /// The length of the horizontal halfaxis. /// </param> /// <param name="thickness"> /// The length of the vertical halfaxis. /// </param> /// <param name="startPos"> /// The initial position. /// </param> /// <param name="startAngl"> /// The inital anlge. /// </param> /// <param name="activeStress"> /// The active stress excerted on the fluid by the particle. Zero for passive particles. /// </param> /// <param name="startTransVelocity"> /// The inital translational velocity. /// </param> /// <param name="startRotVelocity"> /// The inital rotational velocity. /// </param> public Particle_Rectangle(ParticleMotionInit motionInit, double length = 4, double thickness = 1, double[] startPos = null, double startAngl = 0, double activeStress = 0, double[] startTransVelocity = null, double startRotVelocity = 0) : base(motionInit, startPos, startAngl, activeStress, startTransVelocity, startRotVelocity) { m_Length = length; m_Thickness = thickness; Aux.TestArithmeticException(length, "Particle length"); Aux.TestArithmeticException(thickness, "Particle thickness"); Motion.GetParticleLengthscale(GetLengthScales().Max()); Motion.GetParticleMinimalLengthscale(GetLengthScales().Max()); Motion.GetParticleArea(Area); Motion.GetParticleMomentOfInertia(MomentOfInertia); }
/// <summary> /// Calculates the rotational acceleration of the particle using the added damping model. /// </summary> /// <param name="dt">Timestep</param> protected override double CalculateRotationalAcceleration(double dt) { double[,] coefficientMatrix = CalculateCoefficientMatrix(dt); double denominator = CalculateDenominator(coefficientMatrix); double l_Acceleration = GetHydrodynamicForces(0)[0] * (coefficientMatrix[1, 0] * coefficientMatrix[2, 1] - coefficientMatrix[1, 1] * coefficientMatrix[2, 0]); l_Acceleration += GetHydrodynamicForces(0)[1] * (coefficientMatrix[0, 1] * coefficientMatrix[2, 0] - coefficientMatrix[0, 0] * coefficientMatrix[2, 1]); l_Acceleration += GetHydrodynamicTorque(0) * (coefficientMatrix[0, 0] * coefficientMatrix[1, 1] - coefficientMatrix[0, 1] * coefficientMatrix[1, 0]); l_Acceleration /= denominator; Aux.TestArithmeticException(l_Acceleration, "particle rotational acceleration"); return(l_Acceleration); }
/// <summary> /// Constructor for a superellipsoid. /// </summary> /// <param name="motionInit"> /// Initializes the motion parameters of the particle (which model to use, whether it is a dry simulation etc.) /// </param> /// <param name="length"> /// The length of the horizontal halfaxis. /// </param> /// <param name="thickness"> /// The length of the vertical halfaxis. /// </param> /// <param name="superEllipsoidExponent"> /// The exponent of the superellipsoid. /// </param> /// <param name="startPos"> /// The initial position. /// </param> /// <param name="startAngl"> /// The inital anlge. /// </param> /// <param name="activeStress"> /// The active stress excerted on the fluid by the particle. Zero for passive particles. /// </param> /// <param name="startTransVelocity"> /// The inital translational velocity. /// </param> /// <param name="startRotVelocity"> /// The inital rotational velocity. /// </param> public Particle_superEllipsoid(InitializeMotion motionInit, double length, double thickness, int superEllipsoidExponent, double[] startPos = null, double startAngl = 0, double activeStress = 0, double[] startTransVelocity = null, double startRotVelocity = 0) : base(motionInit, startPos, startAngl, activeStress, startTransVelocity, startRotVelocity) { m_Length = length; m_Thickness = thickness; m_Exponent = superEllipsoidExponent; Aux.TestArithmeticException(length, "Particle length"); Aux.TestArithmeticException(thickness, "Particle thickness"); Aux.TestArithmeticException(superEllipsoidExponent, "super ellipsoid exponent"); Motion.SetParticleMaxLengthscale(GetLengthScales().Max()); Motion.SetParticleArea(Area); Motion.SetParticleMomentOfInertia(MomentOfInertia); }
/// <summary> /// Returns the support point of the particle in the direction specified by a vector. /// </summary> /// <param name="vector"> /// A vector. /// </param> override public Vector GetSupportPoint(Vector supportVector, int SubParticleID) { Aux.TestArithmeticException(supportVector, "vector in calc of support point"); if (supportVector.L2Norm() == 0) { throw new ArithmeticException("The given vector has no length"); } double[] position = Motion.GetPosition(0); double angle = Motion.GetAngle(0); double[] subPosition = position.CloneAs(); double[] length = position.CloneAs(); switch (SubParticleID) { case 1: subPosition[0] = position[0] - (m_Height - m_Thickness) / 2 * Math.Sin(angle); subPosition[1] = position[1] - (m_Height - m_Thickness) / 2 * Math.Cos(angle); length[0] = ((m_Length - 2 * m_Thickness) * Math.Cos(angle) - m_Thickness * Math.Sin(angle)) / 2; length[1] = ((m_Length - 2 * m_Thickness) * Math.Sin(angle) + m_Thickness * Math.Cos(angle)) / 2; break; case 2: subPosition[0] = position[0] - (m_Length - m_Thickness) / 2 * Math.Cos(angle); subPosition[1] = position[1] - (m_Length - m_Thickness) / 2 * Math.Sin(angle); length[0] = (m_Thickness * Math.Cos(angle) - m_Height * Math.Sin(angle)) / 2; length[1] = (m_Thickness * Math.Sin(angle) + m_Height * Math.Cos(angle)) / 2; break; case 3: subPosition[0] = position[0] - (-m_Length + m_Thickness) / 2 * Math.Cos(angle); subPosition[1] = position[1] - (-m_Length + m_Thickness) / 2 * Math.Sin(angle); length[0] = (m_Thickness * Math.Cos(angle) - m_Height * Math.Sin(angle)) / 2; length[1] = (m_Thickness * Math.Sin(angle) + m_Height * Math.Cos(angle)) / 2; break; } Vector supportPoint = new Vector(supportVector); Vector rotVector = new Vector(supportVector); rotVector[0] = supportVector[0] * Math.Cos(angle) - supportVector[1] * Math.Sin(angle); rotVector[1] = supportVector[0] * Math.Sin(angle) + supportVector[1] * Math.Cos(angle); for (int d = 0; d < position.Length; d++) { supportPoint[d] = Math.Sign(rotVector[d]) * length[d] + subPosition[d]; } return(supportPoint); }
/// <summary> /// Returns the support point of the particle in the direction specified by a vector. /// </summary> /// <param name="vector"> /// A vector. /// </param> override public double[] GetSupportPoint(double[] vector, int SubParticleID) { Aux.TestArithmeticException(vector, "vector in calc of support point"); if (vector.L2Norm() == 0) { throw new ArithmeticException("The given vector has no length"); } double[] SupportPoint = new double[SpatialDim]; double angle = Motion.GetAngle(0); double[] position = Motion.GetPosition(0); double[,] rotMatrix = new double[2, 2]; rotMatrix[0, 0] = m_Length * Math.Cos(angle); rotMatrix[0, 1] = -m_Thickness *Math.Sin(angle); rotMatrix[1, 0] = m_Length * Math.Sin(angle); rotMatrix[1, 1] = m_Thickness * Math.Cos(angle); double[,] transposeRotMatrix = rotMatrix.CloneAs(); transposeRotMatrix[0, 1] = rotMatrix[1, 0]; transposeRotMatrix[1, 0] = rotMatrix[0, 1]; double[] rotVector = new double[2]; for (int i = 0; i < 2; i++) { for (int j = 0; j < 2; j++) { rotVector[i] += transposeRotMatrix[i, j] * vector[j]; } } rotVector.ScaleV(1 / rotVector.L2Norm()); for (int i = 0; i < 2; i++) { for (int j = 0; j < 2; j++) { SupportPoint[i] += rotMatrix[i, j] * rotVector[j]; } SupportPoint[i] += position[i]; } return(SupportPoint); }
/// <summary> /// Calculates the translational acceleration of the particle using the added damping model. /// </summary> /// <param name="dt">Timestep</param> protected override Vector CalculateTranslationalAcceleration(double dt) { double[,] coefficientMatrix = CalculateCoefficientMatrix(dt); double denominator = CalculateDenominator(coefficientMatrix); Vector l_Acceleration = new Vector(SpatialDim); l_Acceleration[0] = GetHydrodynamicForces(0)[0] * (coefficientMatrix[1, 1] * coefficientMatrix[2, 2] - coefficientMatrix[1, 2] * coefficientMatrix[2, 1]); l_Acceleration[0] += GetHydrodynamicForces(0)[1] * (-coefficientMatrix[0, 1] * coefficientMatrix[2, 2] + coefficientMatrix[0, 2] * coefficientMatrix[2, 1]); l_Acceleration[0] += GetHydrodynamicTorque(0) * (coefficientMatrix[0, 1] * coefficientMatrix[1, 2] - coefficientMatrix[0, 2] * coefficientMatrix[1, 1]); l_Acceleration[0] = l_Acceleration[0] / denominator; l_Acceleration[1] = GetHydrodynamicForces(0)[0] * (-coefficientMatrix[1, 0] * coefficientMatrix[2, 2] + coefficientMatrix[1, 2] * coefficientMatrix[2, 0]); l_Acceleration[1] += GetHydrodynamicForces(0)[1] * (coefficientMatrix[0, 0] * coefficientMatrix[2, 2] - coefficientMatrix[0, 2] * coefficientMatrix[2, 0]); l_Acceleration[1] += GetHydrodynamicTorque(0) * (-coefficientMatrix[0, 0] * coefficientMatrix[1, 2] + coefficientMatrix[0, 2] * coefficientMatrix[1, 0]); l_Acceleration[1] = l_Acceleration[1] / denominator; Aux.TestArithmeticException(l_Acceleration, "particle translational acceleration"); return(l_Acceleration); }
/// <summary> /// Returns the support point of the particle in the direction specified by a vector. /// </summary> /// <param name="vector"> /// A vector. /// </param> override public double[] GetSupportPoint(double[] vector, int SubParticleID) { Aux.TestArithmeticException(vector, "vector in calc of support point"); if (vector.L2Norm() == 0) { throw new ArithmeticException("The given vector has no length"); } double[] supportPoint = vector.CloneAs(); double angle = Motion.GetAngle(0); double[] position = Motion.GetPosition(0); double[] rotVector = vector.CloneAs(); rotVector[0] = vector[0] * Math.Cos(angle) - vector[1] * Math.Sin(angle); rotVector[1] = vector[0] * Math.Sin(angle) + vector[1] * Math.Cos(angle); double[] length = position.CloneAs(); length[0] = m_Length * Math.Cos(angle) - m_Thickness * Math.Sin(angle); length[1] = m_Length * Math.Sin(angle) + m_Thickness * Math.Cos(angle); for (int d = 0; d < position.Length; d++) { supportPoint[d] = Math.Sign(rotVector[d]) * length[d] + position[d]; } return(supportPoint); }
/// <summary> /// Update in every timestep tensors to implement the added damping model (Banks et.al. 2017). /// </summary> internal override void UpdateDampingTensors() { AddedDampingTensor = AddedDamping.RotateTensor(GetAngle(0), m_StartingAngle, AddedDampingTensor); Aux.TestArithmeticException(AddedDampingTensor, "particle added damping tensor"); }