/*
* Copyright 2012 Phil Pratt-Szeliga and other contributors
* http://chirrup.org/
*
* See the file LICENSE for copying permission.
*/
package org.trifort.rootbeer.testcases.rootbeertest.ofcoarse;
public class CoarseningPhysics {
double mCnum;
double mVolumeScale;
double mTimeStep;
double mAgeStep;
double mCurrAge;
int mBorder;
VariableAgeCutoff m_VariableAgeStep;
boolean m_UsingVariableAgeStep;
double mMinAggregateSize;
GpuList<Droplet> mPrevDroplets;
GpuList<GpuNumber> mDebug;
public CoarseningPhysics(){
mMinAggregateSize = 200;
mCnum = 2.8;
mVolumeScale = 0.9;
mTimeStep = 800;
mAgeStep = 1;
m_UsingVariableAgeStep = false;
mDebug = new GpuList<GpuNumber>();
}
public GpuList<GpuNumber> getDebug(){
return mDebug;
}
public GpuList<Droplet> makePrediction(GpuList<Droplet> droplets) {
mPrevDroplets = new GpuList<Droplet>();
for(int i = 0; i < droplets.size(); ++i){
Droplet drop = droplets.get(i);
mPrevDroplets.add(new Droplet(drop));
}
resetDropletAverages();
doPairDropletPrediction();
averageValues();
removeSmallDroplets();
return mergeDroplets();
}
public void setParameters(double cnum, double volumescale, double timestep,
double age_step, int border){
mCnum = cnum;
mVolumeScale = volumescale;
mTimeStep = timestep;
mAgeStep = age_step;
mBorder = border;
m_UsingVariableAgeStep = false;
}
public void setParameters(double cnum, double volumescale, double timestep,
int border, VariableAgeCutoff age_step){
mCnum = cnum;
mVolumeScale = volumescale;
mTimeStep = timestep;
m_VariableAgeStep = age_step;
mBorder = border;
m_UsingVariableAgeStep = true;
}
public void setCurrAge(double curr_age){
mCurrAge = curr_age;
}
double volume_update_drop1(double v1_k, double v2_k, Point x1_k, Point x2_k){
double L_k = PointDistance.distance(x1_k, x2_k);
v1_k *= mVolumeScale;
v2_k *= mVolumeScale;
double term1 = v1_k;
double term2 = mTimeStep * (4 * StrictMath.pow(StrictMath.PI, 4.0/3.0)) / (StrictMath.log(L_k / StrictMath.pow(v1_k, 1.0/3.0)) +
StrictMath.log(L_k / StrictMath.pow(v2_k, 1.0/3.0))) *
(StrictMath.pow(v1_k, -1.0/3.0) - StrictMath.pow(v2_k, -1.0/3.0));
return term1 - term2;
}
double volume_update_drop2(double v1_k, double v2_k, double v1_k_plus_1){
v1_k *= mVolumeScale;
v2_k *= mVolumeScale;
return v2_k - (v1_k_plus_1 - v1_k);
}
double log10(double value){
return StrictMath.log(value) / StrictMath.log(10.0);
}
Point center_update_drop1(Point x1_k, Point x2_k, double v1_k, double v1_k_plus_1){
v1_k *= mVolumeScale;
double g_1 = 2.0 / StrictMath.pow(StrictMath.PI, 2.0/3.0) * mCnum * StrictMath.pow(v1_k, 2.0/3.0);
double L_12 = PointDistance.distance(x1_k, x2_k);
double c_12 = - 1 / (3 * StrictMath.pow(StrictMath.PI, 1.0/3.0)) * StrictMath.pow(L_12, -1) * StrictMath.pow(v1_k, 1.0/3.0) *
log10(v1_k);
double x1_k_plus_1_x = x1_k.X - ((c_12 / g_1)*(v1_k_plus_1 - v1_k));
double x1_k_plus_1_y = x1_k.Y - ((c_12 / g_1)*(v1_k_plus_1 - v1_k));
return new Point(x1_k_plus_1_x, x1_k_plus_1_y);
}
Point center_update_drop2(Point x1_k, Point x2_k, double v1_k, double v1_k_plus_1, double v2_k){
v1_k *= mVolumeScale;
v2_k *= mVolumeScale;
double g_2 = 2.0 / StrictMath.pow(StrictMath.PI, 2.0/3.0) * mCnum * StrictMath.pow(v2_k, 2.0/3.0);
double L_21 = PointDistance.distance(x2_k, x1_k);
double c_21 = - 1 / (3 * StrictMath.pow(StrictMath.PI, 1.0/3.0)) * StrictMath.pow(L_21, -1) * StrictMath.pow(v2_k, 1.0/3.0) *
log10(v2_k);
double x2_k_plus_1_x = x2_k.X - ((c_21 / g_2)*(v1_k_plus_1 - v1_k));
double x2_k_plus_1_y = x2_k.Y - ((c_21 / g_2)*(v1_k_plus_1 - v1_k));
return new Point(x2_k_plus_1_x, x2_k_plus_1_y);
}
private void averageValues() {
for(int i = 0; i < mPrevDroplets.size(); ++i){
Droplet drop = mPrevDroplets.get(i);
drop.finalizePrediction();
if(drop.getVolume() < 0.000000001){
mPrevDroplets.remove(i);
--i;
}
}
}
private void doPairDropletPrediction() {
for(int i = 0; i < mPrevDroplets.size(); ++i){
Droplet drop1 = mPrevDroplets.get(i);
if(drop1.getVolume() < 0.000000001)
continue;
for(int j = i + 1; j < mPrevDroplets.size(); ++j){
Droplet drop2 = mPrevDroplets.get(j);
if(drop2.getVolume() < 0.000000001)
continue;
double drop1_volume;
double drop2_volume;
if(pastAgeStep(drop1.getCenter(), drop2.getCenter())){
drop1_volume = drop1.getVolume();
drop2_volume = drop2.getVolume();
} else {
drop1_volume = volume_update_drop1(drop1.getVolume(), drop2.getVolume(), drop1.getCenter(),
drop2.getCenter());
drop2_volume = volume_update_drop2(drop1.getVolume(), drop2.getVolume(), drop1_volume);
}
if(drop1_volume <= 0.000000001){
continue;
}
if(drop2_volume <= 0.000000001){
continue;
}
if(dropletsTooClose(drop1.getCenter(), drop2.getCenter())){
continue;
}
Point drop1_center = center_update_drop1(drop1.getCenter(), drop2.getCenter(), drop1.getVolume(),
drop1_volume);
Point drop2_center = center_update_drop2(drop1.getCenter(), drop2.getCenter(), drop1.getVolume(),
drop1_volume, drop2.getVolume());
drop1.addNextData(drop1_center, drop1_volume);
drop2.addNextData(drop2_center, drop2_volume);
}
}
}
public Point midpoint(Point p1, Point p2){
double x = (p1.X + p2.X) / 2.0;
double y = (p1.Y + p2.Y) / 2.0;
return new Point(x, y);
}
private GpuList<Droplet> mergeDroplets() {
GpuList<Droplet> output = new GpuList<Droplet>();
for(int i = 0; i < mPrevDroplets.size(); ++i){
Droplet drop1 = mPrevDroplets.get(i);
for(int j = i + 1; j < mPrevDroplets.size(); ++j){
Droplet drop2 = mPrevDroplets.get(j);
double distance = PointDistance.distance(drop1.getCenter(), drop2.getCenter());
double radius1 = drop1.getRadius();
double radius2 = drop2.getRadius();
if(distance - (radius1 + radius2) <= 0){
Point center = midpoint(drop1.getCenter(), drop2.getCenter());
double volume = drop1.getVolume() + drop2.getVolume();
drop1.resetNextData();
drop1.addNextData(center, volume);
drop1.finalizePrediction();
mPrevDroplets.remove(j);
break;
}
}
output.add(new Droplet(drop1));
}
return output;
}
private void removeSmallDroplets() {
for(int i = 0; i < mPrevDroplets.size(); ++i){
Droplet curr = mPrevDroplets.get(i);
if(curr.getVolume() < mMinAggregateSize){
mPrevDroplets.remove(i);
--i;
}
}
}
private void resetDropletAverages() {
for(int i = 0; i < mPrevDroplets.size(); ++i)
mPrevDroplets.get(i).resetNextData();
}
private boolean dropletsTooClose(Point center1, Point center2) {
if(PointDistance.distance(center1, center2) < 0.00000001)
return true;
return false;
}
private boolean pastAgeStep(Point x1_k, Point x2_k) {
if(m_UsingVariableAgeStep == false){
if(mCurrAge > mAgeStep)
return true;
return false;
}
if(m_VariableAgeStep.pastAgeStep(x1_k, mCurrAge))
return true;
if(m_VariableAgeStep.pastAgeStep(x2_k, mCurrAge))
return true;
return false;
}
}