Fixed pinch scattering

This commit is contained in:
Alexander Nozik 2016-06-09 15:51:41 +03:00
parent 6b8445b3e1
commit 88b0cd1c02
12 changed files with 123 additions and 95 deletions

View File

@ -8,7 +8,7 @@ mainClassName = "inr.numass.trapping.Trapping"
group = 'inr.numass' group = 'inr.numass'
version = 'dev' version = 'dev'
description = """trapping""" description = "Numass trapping simulation"
sourceCompatibility = 1.8 sourceCompatibility = 1.8
targetCompatibility = 1.8 targetCompatibility = 1.8
@ -18,9 +18,9 @@ tasks.withType(JavaCompile) {
} }
repositories { repositories {
mavencentral()
maven { url "http://repo.maven.apache.org/maven2" }
} }
dependencies { dependencies {
compile group: 'org.apache.commons', name: 'commons-math3', version:'3.6.1' compile group: 'org.apache.commons', name: 'commons-math3', version:'3.6.1'
testCompile group: 'junit', name: 'junit', version:'4.12' testCompile group: 'junit', name: 'junit', version:'4.12'

1
docs/csource/readme.txt Normal file
View File

@ -0,0 +1 @@
Original C sources provided by Sebastian Voecking and Ferenc Glueck

View File

@ -31,26 +31,58 @@ public class SimulationManager {
return this; return this;
} }
/**
* Select output for accepted events
*
* @param output
* @return
*/
public SimulationManager withOutput(PrintStream output) { public SimulationManager withOutput(PrintStream output) {
this.output = output; this.output = output;
return this; return this;
} }
/**
* Select output for statistics
*
* @param statisticOutput
* @return
*/
public SimulationManager withStatisticOutput(PrintStream statisticOutput) { public SimulationManager withStatisticOutput(PrintStream statisticOutput) {
this.statisticOutput = statisticOutput; this.statisticOutput = statisticOutput;
return this; return this;
} }
/**
* Set field map as function
*
* @param fieldMap
* @return
*/
public SimulationManager withFieldMap(UnivariateFunction fieldMap) { public SimulationManager withFieldMap(UnivariateFunction fieldMap) {
this.simulator.setFieldFunc(fieldMap); this.simulator.setFieldFunc(fieldMap);
return this; return this;
} }
/**
* Set field map from values
*
* @param z
* @param b
* @return
*/
public SimulationManager withFieldMap(double[] z, double[] b) { public SimulationManager withFieldMap(double[] z, double[] b) {
this.simulator.setFieldFunc(new LinearInterpolator().interpolate(z, b)); this.simulator.setFieldFunc(new LinearInterpolator().interpolate(z, b));
return this; return this;
} }
/**
* Set source density
* PENDING replace by source thickness?
*
* @param density
* @return
*/
public SimulationManager withDensity(double density) { public SimulationManager withDensity(double density) {
this.simulator.setGasDensity(density); this.simulator.setGasDensity(density);
return this; return this;
@ -68,7 +100,7 @@ public class SimulationManager {
System.out.printf("%nStarting sumulation with initial energy %g and %d electrons.%n%n", initialE, num); System.out.printf("%nStarting sumulation with initial energy %g and %d electrons.%n%n", initialE, num);
Stream.generate(() -> getRandomTheta()).limit(num).parallel() Stream.generate(() -> getRandomTheta()).limit(num).parallel()
.forEach((theta) -> { .forEach((theta) -> {
double initZ = generator.nextDouble() * Simulator.SOURCE_LENGTH; double initZ = (generator.nextDouble()-1) * Simulator.SOURCE_LENGTH;
Simulator.SimulationResult res = simulator.simulate(initialE, theta, initZ); Simulator.SimulationResult res = simulator.simulate(initialE, theta, initZ);
if (reportIf.test(res)) { if (reportIf.test(res)) {
if (output != null) { if (output != null) {
@ -83,7 +115,7 @@ public class SimulationManager {
private double getRandomTheta() { private double getRandomTheta() {
double x = generator.nextDouble(); double x = generator.nextDouble();
// from 0 to 2 Pi // from 0 to Pi
return Math.acos(1 - 2 * x); return Math.acos(1 - 2 * x);
} }
@ -106,6 +138,9 @@ public class SimulationManager {
} }
/**
* Statistic counter
*/
public static class Counter { public static class Counter {
int accepted = 0; int accepted = 0;
int pass = 0; int pass = 0;

View File

@ -11,11 +11,10 @@ import org.apache.commons.math3.geometry.euclidean.threed.SphericalCoordinates;
import org.apache.commons.math3.geometry.euclidean.threed.Vector3D; import org.apache.commons.math3.geometry.euclidean.threed.Vector3D;
import org.apache.commons.math3.random.JDKRandomGenerator; import org.apache.commons.math3.random.JDKRandomGenerator;
import org.apache.commons.math3.random.RandomGenerator; import org.apache.commons.math3.random.RandomGenerator;
import org.apache.commons.math3.util.DoubleArray;
import org.apache.commons.math3.util.Pair; import org.apache.commons.math3.util.Pair;
import org.apache.commons.math3.util.Precision; import org.apache.commons.math3.util.Precision;
import java.util.function.Function;
import static org.apache.commons.math3.util.FastMath.*; import static org.apache.commons.math3.util.FastMath.*;
/** /**
@ -24,7 +23,7 @@ import static org.apache.commons.math3.util.FastMath.*;
public class Simulator { public class Simulator {
public static final double SOURCE_LENGTH = 3d; public static final double SOURCE_LENGTH = 3d;
private static final double DELTA_L = 0.1; //step for dZ calculation private static final double DELTA_L = 0.1; //step for deltaZ calculation
private RandomGenerator generator; private RandomGenerator generator;
private Scatter scatter; private Scatter scatter;
@ -138,24 +137,45 @@ public class Simulator {
/** /**
* calculate z coordinate change with known path length. Does not change position. * calculate z coordinate change with known path length. Does not change position.
* *
* @param dl * @param deltaL
* @return * @return z shift and reflection counter
*/ */
private double dZ(State position, double dl) { private Pair<Double, Integer> deltaZ(State position, double deltaL) {
// if magnetic field not defined, consider it to be uniform and equal bSource // if magnetic field not defined, consider it to be uniform and equal bSource
int direction = position.isForward() ? 1 : -1;
if (magneticField == null) { if (magneticField == null) {
return dl / cos(position.theta); double deltaZ = direction * deltaL * cos(position.theta);
int reflectionCounter = (int) (deltaZ / SOURCE_LENGTH);
double curZ = normalizeZ(position.z + deltaZ);
return new Pair<>(curZ - position.z, reflectionCounter);
} else { } else {
double dz = 0; int reflect = 0;
double curZ = position.z;
double curL = 0; double curL = 0;
while (curL <= dl) {
double delta = min(dl - curL, DELTA_L);
double b = field(position.z + dz);
dz += delta / sqrt(1 - pow(sin(position.theta), 2) * b / bSource);
curL += DELTA_L; double sin2 = sin(position.theta) * sin(position.theta);
while (curL <= deltaL) {
double delta = DELTA_L; //min(deltaL - curL, DELTA_L);
double b = field(curZ);
//TODO check this!
double root = 1 - sin2 * b / bSource;
// change direction in case of reflection. Loss of precision here?
if (root < 0) {
direction = -direction;
root = -root;
reflect++;
} }
return dz;
curZ += direction * delta * sqrt(root);
curZ = normalizeZ(curZ);
curL += delta;
}
return new Pair<>(curZ - position.z, reflect);
} }
} }
@ -169,18 +189,23 @@ public class Simulator {
if (magneticField == null) { if (magneticField == null) {
return bSource; return bSource;
} else { } else {
while (!(z > 0 && z < SOURCE_LENGTH)) {
// reflecting from back wall
if (z < 0) {
z = -z;
} else {
z -= SOURCE_LENGTH;
}
}
return magneticField.value(z); return magneticField.value(z);
} }
} }
private double normalizeZ(double z) {
while ((abs(z) > SOURCE_LENGTH / 2)) {
if (z < 0) {
// reflecting from rear pinch
z += SOURCE_LENGTH / 2d;
} else {
// reflecting from forward transport magnet
z -= SOURCE_LENGTH / 2d;
}
}
return z;
}
/** /**
* Симулируем один пробег электрона от начального значения и до вылетания из * Симулируем один пробег электрона от начального значения и до вылетания из
* иточника или до того момента, как энергия становится меньше eLow. * иточника или до того момента, как энергия становится меньше eLow.
@ -188,17 +213,7 @@ public class Simulator {
public SimulationResult simulate(double initEnergy, double initTheta, double initZ) { public SimulationResult simulate(double initEnergy, double initTheta, double initZ) {
assert initEnergy > 0; assert initEnergy > 0;
assert initTheta > 0 && initTheta < Math.PI; assert initTheta > 0 && initTheta < Math.PI;
assert initZ >= 0 && initZ < SOURCE_LENGTH; assert abs(initZ) <= SOURCE_LENGTH / 2d;
// if (initTheta < this.thetaPinch) {
// if (generator.nextBoolean()) {
// return new SimulationResult(EndState.PASS, initEnergy, initTheta, initTheta, 0);
// } else {
// return new SimulationResult(EndState.REJECTED, initEnergy, initTheta, initTheta, 0);
// }
// } else if (initTheta < this.thetaTransport) {
// return new SimulationResult(EndState.REJECTED, initEnergy, initTheta, initTheta, 0);
// }
State pos = new State(initEnergy, initTheta, initZ); State pos = new State(initEnergy, initTheta, initZ);
EndState endState = EndState.NONE; EndState endState = EndState.NONE;
@ -208,15 +223,15 @@ public class Simulator {
while (!stopflag) { while (!stopflag) {
double dl = freePath(pos.e); // path to next scattering double dl = freePath(pos.e); // path to next scattering
double dz = dZ(pos, dl); // z coordinate to next scattering Pair<Double, Integer> dzCalc = deltaZ(pos, dl);
double expectedZ = pos.z + dz; // expected z position of next scattering double dz = dzCalc.getFirst();// z coordinate to next scattering
int reflections = dzCalc.getSecond();
//if no scattering on current source pass //if no scattering on current source pass
if (expectedZ < 0 || expectedZ > SOURCE_LENGTH) { if (reflections > 0) {
//accepted by spectrometer //accepted by spectrometer
if (pos.theta < thetaPinch) { if (pos.theta < thetaPinch) {
stopflag = true; stopflag = true;
//Учитываем тот факт, что электрон мог вылететь в правильный угол, но назад
if (pos.colNum == 0) { if (pos.colNum == 0) {
//counting pass electrons //counting pass electrons
endState = EndState.PASS; endState = EndState.PASS;
@ -226,23 +241,22 @@ public class Simulator {
} }
//through the rear magnetic trap //through the rear magnetic pinch
if (pos.theta >= PI - thetaTransport) { if (pos.theta >= PI - thetaTransport) {
stopflag = true; stopflag = true;
endState = EndState.REJECTED; endState = EndState.REJECTED;
} }
if (pos.e < eLow) {
//Если энергия стала слишком маленькой
stopflag = true;
endState = EndState.LOWENERGY;
}
} }
if (!stopflag) { if (!stopflag) {
// perform scatter // perform scatter
propagate(pos, dl, dz); propagate(pos, dl, dz);
pos.colNum++; pos.colNum++;
scatter(pos); scatter(pos);
if (pos.e < eLow) {
//Если энергия стала слишком маленькой
stopflag = true;
endState = EndState.LOWENERGY;
}
} }
} }
@ -312,7 +326,7 @@ public class Simulator {
int colNum = 0; int colNum = 0;
/** /**
* current z; * current z. Zero is the center of the source
*/ */
double z; double z;
@ -337,13 +351,13 @@ public class Simulator {
*/ */
double addZ(double dZ) { double addZ(double dZ) {
this.z += dZ; this.z += dZ;
while (!(this.z > 0 && this.z < SOURCE_LENGTH)) { while (abs(this.z) > SOURCE_LENGTH / 2d) {
// reflecting from back wall // reflecting from back wall
if (z < 0) { if (z < 0) {
z = -z; z += SOURCE_LENGTH / 2d;
flip(); flip();
} else { } else {
z -= SOURCE_LENGTH; z -= SOURCE_LENGTH / 2d;
flip(); flip();
} }
} }
@ -375,7 +389,14 @@ public class Simulator {
if (magneticField == null) { if (magneticField == null) {
return theta; return theta;
} else { } else {
return asin(sin(theta) * sqrt(field() / bSource)); double newTheta = asin(min(abs(sin(theta)) * sqrt(field() / bSource), 1));
if (theta > PI / 2) {
newTheta = PI - newTheta;
}
if (Double.isNaN(newTheta)) {
throw new Error();
}
return newTheta;
} }
} }
@ -406,7 +427,7 @@ public class Simulator {
if (newtheta < 0) { if (newtheta < 0) {
newtheta = -newtheta; newtheta = -newtheta;
} }
if (newtheta > Math.PI && newtheta <= Math.PI * 3 / 2) { if (newtheta > Math.PI) {
newtheta = 2 * Math.PI - newtheta; newtheta = 2 * Math.PI - newtheta;
} }
@ -415,7 +436,15 @@ public class Simulator {
theta = newtheta; theta = newtheta;
} else { } else {
theta = asin(sin(newtheta) * sqrt(bSource / field())); theta = asin(sin(newtheta) * sqrt(bSource / field()));
if (newtheta > PI / 2) {
theta = PI - theta;
} }
}
if (Double.isNaN(theta)) {
throw new Error();
}
return theta; return theta;
} }

View File

@ -26,7 +26,8 @@ public class Trapping {
new SimulationManager() new SimulationManager()
.withParameters(0.6, 3.7, 4.84, 18000d, 4000) .withParameters(0.6, 3.7, 4.84, 18000d, 4000)
// .withFieldMap(z, b) // .withFieldMap(z, b)
.simulateAll((int) 1e4); // .withDensity(5e20)
.simulateAll((int) 1e5);
Instant finishTime = Instant.now(); Instant finishTime = Instant.now();
System.out.printf("%nFinished at %s%n", finishTime.toString()); System.out.printf("%nFinished at %s%n", finishTime.toString());
System.out.printf("Calculation took %s%n", Duration.between(startTime,finishTime).toString()); System.out.printf("Calculation took %s%n", Duration.between(startTime,finishTime).toString());

View File

@ -1,38 +0,0 @@
package hep.dataforge.trapping;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
/**
* Unit test for simple App.
*/
public class AppTest
extends TestCase
{
/**
* Create the test case
*
* @param testName name of the test case
*/
public AppTest( String testName )
{
super( testName );
}
/**
* @return the suite of tests being tested
*/
public static Test suite()
{
return new TestSuite( AppTest.class );
}
/**
* Rigourous Test :-)
*/
public void testApp()
{
assertTrue( true );
}
}