Fixed pinch scattering
This commit is contained in:
parent
6b8445b3e1
commit
88b0cd1c02
@ -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
1
docs/csource/readme.txt
Normal file
@ -0,0 +1 @@
|
|||||||
|
Original C sources provided by Sebastian Voecking and Ferenc Glueck
|
@ -31,27 +31,59 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
public SimulationManager withDensity(double density){
|
/**
|
||||||
|
* Set source density
|
||||||
|
* PENDING replace by source thickness?
|
||||||
|
*
|
||||||
|
* @param density
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
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;
|
||||||
|
@ -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++;
|
||||||
|
}
|
||||||
|
|
||||||
|
curZ += direction * delta * sqrt(root);
|
||||||
|
|
||||||
|
curZ = normalizeZ(curZ);
|
||||||
|
|
||||||
|
curL += delta;
|
||||||
}
|
}
|
||||||
return dz;
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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());
|
||||||
|
Binary file not shown.
Binary file not shown.
@ -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 );
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user