Доповідь команди NaN (Київський природничо-науковий ліцей №145) по задачі №4 «Пробивний електрон» (CETO-2019):
- Презентація (pdf, 1,5 МБ)
- Код:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.Vector;
import java.io.*;
import javax.imageio.ImageIO;
public class Task4
{
/** PSEUDO-INPUT */
static double HORIZONTAL_POS_OFFSET = 0.5;
static double VERTICAL_POS_OFFSET = 1.0;
static double DEFAULT_SPEED = 1.0e+8;
static double DEFAULT_ANGLE = 1.5;
static double DEFAULT_CURRENT = 1.0e-12;
static int DEFAULT_N = 40;
static int DEFAULT_M = 40;
/** PHYSICS */
static double dt = 1e-7;
static double ELECTRON_MASS = 9.10938215e-31;
static double ELECTRON_CHARGE = -1.602176487e-19;
static double EPSILLON_ZERO = 8.854187817e-12;
//static double ELECTRON_MASS = 1.0;
//static double ELECTRON_CHARGE = -1.0;
//static double EPSILLON_ZERO = 1.0;
static double PIXEL_LENGTH = 3.163058078e-22;//(double)Task4.WIRES_INTERVAL;
/** VISUAL */
static int VERTICAL_OFFSET = 20;
static int HORIZONTAL_OFFSET = 20;
static int WIRES_INTERVAL = 15;
static int LEFT_OFFSET = 200;
static int RIGHT_OFFSET = 200;
static int TOP_OFFSET = 200;
static int BOTTOM_OFFSET = 200;
static int WIRE_RADIUS = 5;
static int ELECTRON_RADIUS = 10;
/** GABA */
static int SCREEN_RESOLUTION_WIDTH = 1920;
static int SCREEN_RESOLUTION_HEIGHT = 1080;
static int REPITIONS_PER_PART = 100000;
static int UPDATE_FREQUENCY = 10;
//static int UPDATE_FREQUENCY = (int)(1.0e+22/PIXEL_LENGTH);
static LaunchFrame ui;
/** MASSIVE */
static double MAX_SPEED = 100.0;
static double MIN_SPEED = 0.0;
static int SPEED_RESOLUTION = 100;
static double MAX_ANGLE = Math.PI;
static double MIN_ANGLE = 0.0;
static int ANGLE_RESOLUTION = 100;
public static void main (String[] args)
{
ui = new LaunchFrame();
}
}
class LaunchFrame extends JFrame
{
JTextField fieldSpeed;
JTextField fieldAngle;
JTextField fieldN;
JTextField fieldM;
JTextField fieldI;
JTextField fieldDT;
JTextField fieldMinSpeed;
JTextField fieldMaxSpeed;
JTextField fieldResoSpeed;
JLabel areaLog;
public LaunchFrame ()
{
setTitle("Task4");
this.setSize(300, 15*18+200);
this.setResizable(false);
this.setLayout(null);
JLabel labelN = new JLabel("M:", SwingConstants.CENTER);
this.add(labelN);
labelN.setBounds(10, 15, 30, 30);
fieldN = new JTextField();
fieldN.setText(Task4.DEFAULT_N + "");
this.add(fieldN);
fieldN.setBounds(45, 15, 100, 30);
JLabel labelM = new JLabel("N:", SwingConstants.CENTER);
this.add(labelM);
labelM.setBounds(10, 15*4, 30, 30);
fieldM = new JTextField();
fieldM.setText(Task4.DEFAULT_M + "");
this.add(fieldM);
fieldM.setBounds(45, 15*4, 100, 30);
JLabel labelSpeed = new JLabel("S:", SwingConstants.CENTER);
this.add(labelSpeed);
labelSpeed.setBounds(10, 15*10, 30, 30);
fieldSpeed = new JTextField();
fieldSpeed.setText(Task4.DEFAULT_SPEED + "");
this.add(fieldSpeed);
fieldSpeed.setBounds(45, 15*10, 100, 30);
JLabel labelI = new JLabel("I:", SwingConstants.CENTER);
this.add(labelI);
labelI.setBounds(10, 15*7, 30, 30);
fieldI = new JTextField();
fieldI.setText(Task4.DEFAULT_CURRENT + "");
this.add(fieldI);
fieldI.setBounds(45, 15*7, 100, 30);
JLabel labelAngle = new JLabel("A:", SwingConstants.CENTER);
this.add(labelAngle);
labelAngle.setBounds(10, 15*13, 30, 30);
fieldAngle = new JTextField();
fieldAngle.setText(Task4.DEFAULT_ANGLE + "");
this.add(fieldAngle);
fieldAngle.setBounds(45, 15*13, 100, 30);
JButton startButton = new JButton("Create");
class StartListener implements ActionListener
{
public void actionPerformed (ActionEvent e)
{
try
{
Experiment a = new Experiment(Integer.valueOf(Task4.ui.fieldN.getText()), Integer.valueOf(Task4.ui.fieldM.getText()), Double.valueOf(Task4.ui.fieldI.getText()), Double.valueOf(Task4.ui.fieldSpeed.getText()), Double.valueOf(Task4.ui.fieldAngle.getText()), true);
}
catch (NumberFormatException ex)
{
log("Invalid input\n");
ex.printStackTrace();
return;
}
log("Initing experiment");
}
}
startButton.addActionListener(new StartListener());
this.add(startButton);
startButton.setBounds(10, 15*16, 135, 30);
JLabel labelDT = new JLabel("dt:");
this.add(labelDT);
labelDT.setBounds(155, 15, 30, 30);
fieldDT = new JTextField(Double.toString(Task4.dt));
this.add(fieldDT);
fieldDT.setBounds(190, 15, 95, 30);
JLabel labelMaxSpeed = new JLabel("MxS:");
this.add(labelMaxSpeed);
labelMaxSpeed.setBounds(155, 15*4, 30, 30);
fieldMaxSpeed = new JTextField(Double.toString(Task4.MAX_SPEED));
this.add(fieldMaxSpeed);
fieldMaxSpeed.setBounds(190, 15*4, 95, 30);
JLabel labelMinSpeed = new JLabel("MnS:");
this.add(labelMinSpeed);
labelMinSpeed.setBounds(155, 15*7, 30, 30);
fieldMinSpeed = new JTextField(Double.toString(Task4.MIN_SPEED));
this.add(fieldMinSpeed);
fieldMinSpeed.setBounds(190, 15*7, 95, 30);
JLabel labelResoSpeed = new JLabel("SR:");
this.add(labelResoSpeed);
labelResoSpeed.setBounds(155, 15*10, 30, 30);
fieldResoSpeed = new JTextField(Integer.toString(Task4.SPEED_RESOLUTION));
this.add(fieldResoSpeed);
fieldResoSpeed.setBounds(190, 15*10, 95, 30);
JButton saveButton = new JButton("Save consts");
class SaveListener implements ActionListener
{
public void actionPerformed (ActionEvent e)
{
try
{
Task4.dt = Double.valueOf(fieldDT.getText());
Task4.MAX_SPEED = Double.valueOf(fieldMaxSpeed.getText());
Task4.MIN_SPEED = Double.valueOf(fieldMinSpeed.getText());
Task4.SPEED_RESOLUTION = Integer.valueOf(fieldResoSpeed.getText());
}
catch (NumberFormatException ex)
{
log("Invalid input");
ex.printStackTrace();
}
}
}
saveButton.addActionListener(new SaveListener());
this.add(saveButton);
saveButton.setBounds(155, 15*13, 135, 30);
JButton arrayButton = new JButton("Simulate");
class SimulateListener implements ActionListener
{
public void actionPerformed (ActionEvent e)
{
class ui1 extends Thread
{
public void run()
{
try
{
ExperimentSimulation a = new ExperimentSimulation(Integer.valueOf(Task4.ui.fieldN.getText()), Integer.valueOf(Task4.ui.fieldM.getText()), Double.valueOf(Task4.ui.fieldI.getText()));
a.start();
}
catch (NumberFormatException ex)
{
log("Invalid input\n");
ex.printStackTrace();
return;
}
log("Simulation Created");
}
}
new ui1().start();
}
}
arrayButton.addActionListener(new SimulateListener());
this.add(arrayButton);
arrayButton.setBounds(155, 15*16, 135, 30);
this.setVisible(true);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public void log (String s)
{
System.out.println(s);
}
}
class Experiment extends Thread
{
JButton keepButton;
int N;
int M;
double I;
double speed;
double angle;
double offset;
Vect3D pos;
Vect3D vel;
Vect3D amp;
Vect3D acc;
Vect3D ind;
Vect3D lastUpdate;
Vect3D rad;
boolean isVisual;
Vect3D[][] wires;
Canvas f;
int step;
Vector<MPoint> way;
public enum State
{
WAITING,
STARTED,
PAUSED,
ENDED
}
State state;
public Experiment (int N_, int M_, double I_, double speed_, double angle_, boolean isVisual_)
{
N = N_;
M = M_;
I = I_;
speed = speed_;
angle = angle_;
isVisual = isVisual_;
pos = new Vect3D(((N-1)*Task4.WIRES_INTERVAL + Task4.LEFT_OFFSET + Task4.RIGHT_OFFSET)*Task4.HORIZONTAL_POS_OFFSET,
((M-1)*Task4.WIRES_INTERVAL + Task4.TOP_OFFSET + Task4.BOTTOM_OFFSET)*Task4.VERTICAL_POS_OFFSET, 0);
vel = new Vect3D(Math.cos(angle)*speed, -Math.sin(angle)*speed, 0.0);
acc = new Vect3D(0,0,0);
wires = new Vect3D[N][M];
for (int i=0; i<N; i++)
{
for (int j=0; j<M; j++)
{
wires[i][j] = new Vect3D(Task4.LEFT_OFFSET + (i+1)*Task4.WIRES_INTERVAL, Task4.TOP_OFFSET + (j+1)*Task4.WIRES_INTERVAL,0.0);
}
}
amp = new Vect3D(0.0,0.0,I);
if (isVisual)
{
ExperimentFrame visual = new ExperimentFrame();
}
lastUpdate = new Vect3D(pos);
step = 0;
this.state = State.WAITING;
log("Experiment " + this.getName() + " Created");
}
class ExperimentFrame extends JFrame
{
public ExperimentFrame ()
{
setSize(Math.min(Task4.WIRES_INTERVAL*(N-1) + Task4.HORIZONTAL_OFFSET + Task4.LEFT_OFFSET + Task4.RIGHT_OFFSET, Task4.SCREEN_RESOLUTION_WIDTH), Math.min(Task4.VERTICAL_OFFSET*4 + Task4.WIRES_INTERVAL*(M-1) + Task4.TOP_OFFSET + Task4.BOTTOM_OFFSET, Task4.SCREEN_RESOLUTION_HEIGHT));
setResizable(true);
setLayout(new FlowLayout());
class VisualField extends Canvas
{
public VisualField()
{
setSize(Math.min(Task4.WIRES_INTERVAL*(N-1) + Task4.TOP_OFFSET + Task4.BOTTOM_OFFSET, Task4.SCREEN_RESOLUTION_WIDTH), Math.min(Task4.WIRES_INTERVAL*(M-1) + Task4.LEFT_OFFSET + Task4.RIGHT_OFFSET, Task4.SCREEN_RESOLUTION_HEIGHT));
way = new Vector<MPoint>(0);
way.add(new MPoint(pos.x, pos.y));
}
public void paint (Graphics g)
{
g.setColor(Color.BLACK);
for (int i=0; i<M; i++)
{
for (int j=0; j<N; j++)
{
g.fillOval((j)*Task4.WIRES_INTERVAL + Task4.LEFT_OFFSET, (i)*(Task4.WIRES_INTERVAL) + Task4.TOP_OFFSET, Task4.WIRE_RADIUS, Task4.WIRE_RADIUS);
}
}
g.setColor(Color.BLUE);
for (int i=1; i<way.size(); i++)
{
g.drawLine((int)way.elementAt(i-1).x, (int)way.elementAt(i-1).y, (int)way.elementAt(i).x, (int)way.elementAt(i).y);
}
//g.fillOval((int)pos.x,(int)pos.y,Task4.ELECTRON_RADIUS,Task4.ELECTRON_RADIUS);
}
}
f = new VisualField();
f.repaint();
add(f);
keepButton = new JButton("Start experiment");
class keepExperimentTread extends Thread
{
public void run ()
{
run_Mirror();
}
}
class keepListener implements ActionListener
{
public void actionPerformed (ActionEvent e)
{
switch (state)
{
case WAITING:
state = State.STARTED;
keepButton.setText("Pause experiment");
new keepExperimentTread().start();
break;
case STARTED:
state = State.PAUSED;
f.repaint();
keepButton.setText("Continue experiment");
break;
case PAUSED:
state = State.STARTED;
keepButton.setText("Pause experiment");
new keepExperimentTread().start();
break;
case ENDED:
log("Experiment ended");
keepButton.setEnabled(false);
}
}
}
keepButton.addActionListener(new keepListener());
add(keepButton);
JButton reDrawButton = new JButton ("Redraw");
class reDrawListener implements ActionListener
{
public void actionPerformed (ActionEvent e)
{
f.repaint();
}
}
reDrawButton.addActionListener(new reDrawListener());
add(reDrawButton);
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
setVisible(true);
}
public void run_Mirror()
{
run();
}
}
public void run ()
{
this.state = State.STARTED;
while (state == State.STARTED)
{
//System.out.println("Current acc - " + acc.tostring());
step++;
move();
calculateAcc();
calculateVel();
if (isVisual)
{
way.add(new MPoint(pos.x, pos.y));
}
/*if ((pos.add(lastUpdate.multiply(-1.0)).mod() >= Task4.UPDATE_FREQUENCY)&&(isVisual))
{
lastUpdate = new Vect3D(pos);
f.repaint();
}*/
if ((step%5000==0)&&(isVisual))
{
f.repaint();
}
if (checkEnded())
{
state = State.ENDED;
if (isVisual)
{
keepButton.setEnabled(false);
keepButton.setText("Experiment ended");
f.repaint();
}
log("Experiment " + this.getName() + " ended at step " + this.step);
}
yield();
}
}
public boolean checkEnded ()
{
//return((vel.y>0)||(pos.y<0));
return((pos.x<0)||(pos.y<0))||(pos.x>(Task4.WIRES_INTERVAL*(N-1) + Task4.TOP_OFFSET + Task4.BOTTOM_OFFSET))||(pos.y>(Task4.WIRES_INTERVAL*(M-1) + Task4.LEFT_OFFSET + Task4.RIGHT_OFFSET));
//return((pos.y<0)||(pos.y>(Task4.WIRES_INTERVAL*(M-1) + Task4.LEFT_OFFSET + Task4.RIGHT_OFFSET)));
//return(pos.y<0);
}
/*public void calculateAcc ()
{
ind = new Vect3D(0.0,0.0,0.0);
Vect3D rad;
for (int i=0; i<N; i++)
{
for (int j=0; j<M; j++)
{
rad = pos.add(wires[i][j].multiply(-1.0)).multiply(Task4.PIXEL_LENGTH);
rad.z = 0;
ind = ind.add(amp.multiply(rad).multiply(1/(rad.mod()*rad.mod()))).multiply(Task4.ELECTRON_CHARGE/(2.0*Math.PI*Task4.EPSILLON_ZERO)); //add consts
}
}
acc = vel.multiply(ind).multiply(1.0/Task4.ELECTRON_MASS);
}*/
public void move ()
{
pos = pos.add(new Vect3D(vel.x*Task4.dt, vel.y*Task4.dt, vel.z*Task4.dt));
}
public void calculateVel()
{
vel = vel.add(new Vect3D(acc.x*Task4.dt, acc.y*Task4.dt, acc.z*Task4.dt));
vel = vel.multiply(this.speed/vel.mod());
}
public void calculateAcc()
{
acc = new Vect3D(0.0,0.0,0.0);
for(int i=0; i<N; i++)
{
for(int j=0; j<M; j++)
{
rad = Vect3D.add(pos, wires[i][j].multiply(-1));
rad.z=0;
acc = acc.add(new Vect3D(Task4.ELECTRON_CHARGE*this.I*rad.x*vel.z/2/Math.PI/Task4.EPSILLON_ZERO/Task4.ELECTRON_MASS/rad.mod()/rad.mod(),Task4.ELECTRON_CHARGE*this.I*rad.y*vel.z/2/Math.PI/Task4.EPSILLON_ZERO/Task4.ELECTRON_MASS/rad.mod()/rad.mod(), -Task4.ELECTRON_CHARGE*this.I*(pos.y*vel.y + pos.x*vel.x)/2/Math.PI/Task4.EPSILLON_ZERO/Task4.ELECTRON_MASS/rad.mod()/rad.mod()));
}
}
}
public void log (String s)
{
Task4.ui.log(s);
}
}
class ExperimentSimulation extends Thread
{
int N;
int M;
double I;
Canvas d;
boolean[][] isEnded;
Experiment[][] exps;
Vector<MPoint> way = new Vector<MPoint>(0);
int Thread_Count = Task4.SPEED_RESOLUTION*Task4.ANGLE_RESOLUTION;
public enum State
{
WAITING,
STARTED,
PAUSED,
ENDED
}
public State state;
public ExperimentSimulation(int N_, int M_, double I_)
{
this.setName("Experiment Simulation");
N = N_;
M = M_;
I = I_;
isEnded = new boolean[Task4.SPEED_RESOLUTION][Task4.ANGLE_RESOLUTION];
class ExperimentSimulationFrame extends JFrame
{
public ExperimentSimulationFrame ()
{
setSize(Task4.LEFT_OFFSET + Task4.RIGHT_OFFSET + Task4.SPEED_RESOLUTION, Task4.TOP_OFFSET + Task4.BOTTOM_OFFSET + Task4.ANGLE_RESOLUTION);
setLayout(null);
setResizable(false);
class ExperimentSimulationField extends Canvas
{
public ExperimentSimulationField ()
{
setSize(Task4.SPEED_RESOLUTION, Task4.ANGLE_RESOLUTION);
}
public void paint (Graphics g)
{
g.setColor(Color.BLACK);
/*for (int i = 0; i< way.size(); i++)
{
g.drawLine((int)way.elementAt(i).x, (int)way.elementAt(i).y, (int)way.elementAt(i).x, (int)way.elementAt(i).y);
try
{
Thread.sleep(10);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}*/
for (int i=0; i<Task4.SPEED_RESOLUTION; i++)
{
for(int j=0; j<Task4.ANGLE_RESOLUTION; j++)
{
if (isEnded[i][j])
{
g.drawLine(i,j,i,j);
}
}
}
}
}
d = new ExperimentSimulationField();
add(d);
d.setBounds(Task4.LEFT_OFFSET, Task4.TOP_OFFSET, Task4.LEFT_OFFSET + Task4.SPEED_RESOLUTION, Task4.TOP_OFFSET + Task4.ANGLE_RESOLUTION);
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
setVisible(true);
}
}
ExperimentSimulationFrame esf = new ExperimentSimulationFrame();
exps = new Experiment[Task4.SPEED_RESOLUTION][Task4.ANGLE_RESOLUTION];
for (int i=0; i<Task4.SPEED_RESOLUTION; i++)
{
for (int j=0; j<Task4.ANGLE_RESOLUTION; j++)
{
exps[i][j] = new Experiment (N, M, I, Task4.MIN_SPEED + (j+1)*(Task4.MAX_SPEED-Task4.MIN_SPEED)/(Task4.SPEED_RESOLUTION+1), Task4.MIN_ANGLE + i*(Task4.MAX_ANGLE-Task4.MIN_ANGLE)/Task4.ANGLE_RESOLUTION, false);
exps[i][j].setName(this.getName() + " experiment " + i + " " + j);
System.out.println("Named " + exps[i][j].getName());
}
}
state = State.WAITING;
}
public void run()
{
Experiment makhmudov = new Experiment(0,0,0,0,0,false);
makhmudov.state = Experiment.State.ENDED;
if (state == State.WAITING)
{
for (int i=0; i<Task4.SPEED_RESOLUTION; i++)
{
for (int j=0; j<Task4.ANGLE_RESOLUTION; j++)
{
exps[i][j].start();
}
}
}
state = State.STARTED;
int ch = 0;
int turn = 0;
while (state == State.STARTED)
{
try
{
Thread.sleep(30);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
for (int i=0; i<Task4.SPEED_RESOLUTION; i++)
{
for (int j=0; j<Task4.ANGLE_RESOLUTION; j++)
{
if ((exps[i][j].state == Experiment.State.ENDED)&&(!isEnded[i][j]))
{
isEnded[i][j] = true;
way.add(new MPoint(i,j));
exps[i][j] = makhmudov;
ch++;
Thread_Count--;
}
}
}
if (ch > 10)
{
d.repaint();
ch = 0;
System.gc();
}
turn++;
System.out.println(turn + " turn spent, " + Thread_Count + " running");
if (Thread_Count == 0)
{
this.state = State.ENDED;
}
yield();
}
}
}
class Vect3D
{
double x;
double y;
double z;
public Vect3D (double x_, double y_, double z_)
{
x = x_;
y = y_;
z = z_;
}
public Vect3D (Vect3D a)
{
this.x = a.x;
this.y = a.y;
this.z = a.z;
}
public Vect3D multiply (double a)
{
return (new Vect3D(this.x*a, this.y*a, this.z*a));
}
public Vect3D multiply (Vect3D a)
{
return(new Vect3D(this.y*a.z-this.z*a.y, this.x*a.z-this.z*a.x, this.x*a.y-this.y*a.x));
}
public static Vect3D add(Vect3D addition1, Vect3D addition2)
{
return(new Vect3D(addition1.x + addition2.x, addition1.y + addition2.y, addition1.z + addition2.z));
}
public Vect3D add(Vect3D addition)
{
return(new Vect3D(this.x + addition.x, this.y + addition.y, this.z + addition.z));
}
public double mod ()
{
return(Math.sqrt(this.x*this.x + this.y*this.y + this.z*this.z));
}
public String tostring () //was used for debug
{
return (this.x + " " + this.y + " " + this.z);
}
}
class MPoint
{
double x;
double y;
public MPoint (double x_, double y_)
{
this.x = x_;
this.y = y_;
}
}
Возможно, я неверно понимаю условия олимпиады в целом? Речь ведь идет не о том, чтобы написать программу, пусть даже с красивой визуализацией – это ведь не более чем программирование. Но олимпиада ведь по МОДЕЛИРОВАНИЮ, так что главное, как мне кажется – это, имея модель и программу, провести вычислительный эксперимент, набрать статистику, сделать ФИЗИЧЕСКИЕ выводы – вплоть до оценки погрешностей 🙂
В задаче был вопрос, при каких условиях движение будет хаотическим, при каких – электрон будет проходить стенку насквозь? Хотелось бы посмотреть именно это решение, а не просто код программы…
Мы публикуем материалы, предоставленные командой. Беседы на защите касались многих вопросов, в том числе и физики, и использованных технологий. Но конечно, были вопросы, которые остались без ответов.