package gdsc.smlm.model;
import org.apache.commons.math3.random.RandomGenerator;
/*-----------------------------------------------------------------------------
* GDSC SMLM Software
*
* Copyright (C) 2013 Alex Herbert
* Genome Damage and Stability Centre
* University of Sussex, UK
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*---------------------------------------------------------------------------*/
/**
* Contains a model for a moving molecule.
*/
public class MoleculeModel
{
private int id;
protected double[] xyz;
protected double mass;
/**
* Create a new molecule
*
* @param id
* @param xyz
* [x,y,z]
*/
public MoleculeModel(int id, double[] xyz)
{
this.id = id;
this.xyz = xyz;
}
/**
* Create a new molecule
*
* @param id
* @param x
* @param y
* @param z
*/
public MoleculeModel(int id, double x, double y, double z)
{
this.id = id;
xyz = new double[] { x, y, z };
}
/**
* Create a new molecule
*
* @param mass
* @param xyz
* [x,y,z]
*/
public MoleculeModel(double mass, double[] xyz)
{
this.mass = mass;
this.xyz = xyz;
}
/**
* Create a new molecule
*
* @param mass
* @param x
* @param y
* @param z
*/
public MoleculeModel(double mass, double x, double y, double z)
{
this.mass = mass;
xyz = new double[] { x, y, z };
}
/**
* Create a new molecule
*
* @param id
* @param mass
* @param xyz
* [x,y,z]
*/
public MoleculeModel(int id, double mass, double[] xyz)
{
this.id = id;
this.mass = mass;
this.xyz = xyz;
}
/**
* Create a new molecule
*
* @param id
* @param mass
* @param x
* @param y
* @param z
*/
public MoleculeModel(int id, double mass, double x, double y, double z)
{
this.id = id;
this.mass = mass;
xyz = new double[] { x, y, z };
}
/**
* @return the x
*/
public double getX()
{
return xyz[0];
}
/**
* @return the y
*/
public double getY()
{
return xyz[1];
}
/**
* @return the z
*/
public double getZ()
{
return xyz[2];
}
/**
* @return the id
*/
public int getId()
{
return id;
}
/**
* Package level set method to allow renumbering
* @param id
*/
void setId(int id)
{
this.id = id;
}
/**
* @return the mass
*/
public double getMass()
{
return mass;
}
/**
* @return The coordinates (x,y,z)
*/
public double[] getCoordinates()
{
return xyz;
}
/**
* Move the molecule using a random Gaussian shift with standard deviation of the given diffusion rate.
* <p>
* Note: The array provided by {@link #getCoordinates()} is updated and returned.
*
* @param diffusionRate Diffusion rate for each dimension
* @param random Random generator
* @return The new coordinates
*/
public double[] move(double diffusionRate, RandomGenerator random)
{
double[] xyz = getCoordinates();
if (diffusionRate > 0)
{
for (int i = 0; i < 3; i++)
{
final double shift = random.nextGaussian() * diffusionRate;
// Clip the movement
//if (shift > 5*diffusionRate)
// xyz[i] += 5*diffusionRate;
//else if (shift < -5*diffusionRate)
// xyz[i] -= 5*diffusionRate;
//else
xyz[i] += shift;
}
}
return xyz;
}
/**
* Move the molecule using a random Gaussian shift with standard deviation of the given diffusion rate.
* <p>
* Note: The array provided by {@link #getCoordinates()} is updated and returned.
*
* @param diffusionRate Diffusion rate for each dimension
* @param random Random generator (one per dimension)
* @return The new coordinates
*/
public double[] move(double diffusionRate, RandomGenerator[] random)
{
double[] xyz = getCoordinates();
if (diffusionRate > 0)
{
for (int i = 0; i < 3; i++)
{
final double shift = random[i].nextGaussian() * diffusionRate;
// Clip the movement
//if (shift > 5*diffusionRate)
// xyz[i] += 5*diffusionRate;
//else if (shift < -5*diffusionRate)
// xyz[i] -= 5*diffusionRate;
//else
xyz[i] += shift;
}
}
return xyz;
}
/**
* Move the molecule using a random walk with the given step size
* <p>
* Note: The array provided by {@link #getCoordinates()} is updated and returned.
*
* @param stepSize Step size for each dimension
* @param random Random generator
* @return The new coordinates
*/
public double[] walk(double stepSize, RandomGenerator random)
{
double[] xyz = getCoordinates();
if (stepSize > 0)
{
for (int i = 0; i < 3; i++)
{
if (random.nextDouble() < 0.5)
xyz[i] += stepSize;
else
xyz[i] -= stepSize;
}
}
return xyz;
}
/**
* Move the molecule using a random walk with the given step size
* <p>
* Note: The array provided by {@link #getCoordinates()} is updated and returned.
*
* @param stepSize Step size for each dimension
* @param random Random generator (one per dimension)
* @return The new coordinates
*/
public double[] walk(double stepSize, RandomGenerator[] random)
{
double[] xyz = getCoordinates();
if (stepSize > 0)
{
for (int i = 0; i < 3; i++)
{
if (random[i].nextDouble() < 0.5)
xyz[i] += stepSize;
else
xyz[i] -= stepSize;
}
}
return xyz;
}
/**
* Slide the molecule along a unit vector using a random Gaussian shift with standard deviation of the given diffusion rate.
* <p>
* Note: The array provided by {@link #getCoordinates()} is updated and returned.
*
* @param diffusionRate Diffusion rate for 3D diffusion
* @param axis The linear axis to move along (must be a unit vector)
* @param random Random number generator
* @return The new coordinates
*/
public double[] slide(double diffusionRate, double[] axis, RandomGenerator random)
{
double[] xyz = getCoordinates();
if (diffusionRate > 0)
{
final double shift;
// Sample from a Gaussian - This may only be relevant for 1D diffusion
shift = random.nextGaussian() * diffusionRate;
// Sample from the cumulative probability distribution for the MSD.
// Then get a square root to find the shift and assign a direction
//RandomDataGenerator r = new RandomDataGenerator(random);
//shift = ((random.nextDouble() < 0.5) ? 1 : -1) * Math.sqrt(r.nextExponential(diffusionRate*diffusionRate));
// Clip the movement
//if (shift > 5*diffusionRate)
// shift = 5*diffusionRate;
//else if (shift < -5*diffusionRate)
// shift = -5*diffusionRate;
for (int i = 0; i < 3; i++)
{
xyz[i] += shift * axis[i];
}
}
return xyz;
}
}