Skip to content

Commit 5f29566

Browse files
authored
Merge pull request #15 from xsuite/release/v0.1.6
Release 0.1.6
2 parents df2dfa1 + 5e2979e commit 5f29566

29 files changed

+1234
-614
lines changed

.gitignore

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -143,12 +143,6 @@ dmypy.json
143143
# VSCode
144144
.vscode/
145145

146-
# CMake
147-
CMakeCache*.txt
148-
CMakeFiles*/
149-
Makefile*
150-
cmake_install*.cmake
151-
152146
# SixTrack
153147
fort.??*
154148
*.so

examples/results.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
list_of_succeeded_jobs = []
44
user='ddicroce'
5-
studyname='example_study'
6-
for jobname, new_particles in xb.RetrieveJobs(user=user, study=studyname):
7-
print(jobname)
5+
study_name='example_study'
6+
for new_particles, jobinfo in xb.RetrieveJobs(user=user, study_name=study_name):
7+
print(jobinfo)
88
print(f"Particles: {new_particles.at_turn}")

examples/submission.py

Lines changed: 27 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -12,34 +12,31 @@
1212

1313

1414
user = 'sixtadm'
15-
16-
17-
num_turns = 2000
18-
num_particles = 1e6
19-
line = xt.Line(elements=[
20-
xt.Drift(length=1.0), xt.Multipole(knl=[1e-6]), xt.Drift(length=1.0)])
21-
22-
particles_per_sub = 1000
23-
24-
studyname = "example_study"
25-
26-
27-
# Submission can be done in a context, where the submission
28-
# itself is triggered when exiting the context
29-
with xb.SubmitJobs(user=user, study=studyname) as submitter:
30-
for i in range(int(num_particles/particles_per_sub)):
31-
particles = xp.Particles(x=np.random.normal(0, 0.0001, particles_per_sub),
32-
y=np.random.normal(0, 0.0001, particles_per_sub))
33-
submitter.add(job_name=f'{studyname}_{i}', num_turns=num_turns, line=line, particles=particles,
34-
checkpoint_every=100)
35-
36-
37-
# Or by manually triggering the submission
38-
submitter = xb.SubmitJobs(user=user, study=studyname)
39-
for i in range(int(num_particles/particles_per_sub)):
40-
particles = xp.Particles(x=np.random.normal(0, 0.0001, particles_per_sub),
41-
y=np.random.normal(0, 0.0001, particles_per_sub))
42-
submitter.add(job_name=f'{studyname}_{i}', num_turns=num_turns, line=line, particles=particles,
43-
checkpoint_every=100)
44-
submitter.submit()
15+
line = xt.Line.from_json(xb._pkg_root.parent / 'tests' / 'data' / 'sequence_lhc_run3_b1.json')
16+
line.build_tracker()
17+
18+
# Each of these jobs takes ~3h (~3500 particle*turns / second)
19+
num_jobs = 250
20+
num_part_per_job = 400
21+
num_turns = 100000
22+
checkpoint_every = 1000
23+
24+
all_part = line.build_particles(x_norm=np.random.normal(0, 10, num_part_per_job*num_jobs),
25+
y_norm=np.random.normal(0, 10, num_part_per_job*num_jobs),
26+
nemitt_x=3.5e-6, nemitt_y=3.5e-6)
27+
28+
study_name = "example_study"
29+
jobs = xb.SubmitJobs(user=user, study_name=study_name, line=line, dev_server=True)
30+
prev = time.time()
31+
for i in range(num_jobs):
32+
# select subgroup of particles
33+
this_part = all_part.filter((all_part.particle_id>=i*num_part_per_job) \
34+
& (all_part.particle_id<(i+1)*num_part_per_job))
35+
# create job
36+
jobs.add(job_name=f'job{i}', num_turns=num_turns, particles=this_part,
37+
checkpoint_every=checkpoint_every)
38+
# output progress
39+
if i%25 == 24:
40+
now = time.time() ; print(f"{i+1}/{num_jobs} ({now-prev:.4}s)"); prev = now
41+
jobs.submit()
4542

examples/timing.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import subprocess
2+
import time
3+
from pathlib import Path
4+
import numpy as np
5+
6+
import xtrack as xt
7+
import xboinc as xb
8+
9+
line = xt.Line.from_json('../tests/data/sequence_lhc_run3_b1.json')
10+
line.build_tracker()
11+
file_in = Path('xboinc_input.bin')
12+
file_out = Path('sim_state_out.bin')
13+
14+
num_part = 200
15+
num_turns = 50
16+
checkpoint_every = 10
17+
18+
part = line.build_particles(x_norm=np.random.normal(0, 10, num_part),
19+
y_norm=np.random.normal(0, 10, num_part),
20+
nemitt_x=3.5e-6, nemitt_y=3.5e-6)
21+
22+
xb.SimConfig.build(filename=file_in, num_turns=num_turns, line=line,
23+
particles=part, checkpoint_every=checkpoint_every)
24+
25+
print("")
26+
now = time.time()
27+
cmd = subprocess.run(['running/xboinc_0.1-x86_64-pc-linux-gnu'])
28+
print(f"Tracking with executable: done in {time.time()-now:.1f}s")
29+
line.track(part, num_turns=num_turns, time=True)
30+
print(f"Tracking from within python: done in {line.time_last_track:.1f}s.")
31+
32+
exec_part = xb.SimState.from_binary(file_out).particles
33+
assert np.all(part.state == exec_part.state)
34+
assert np.allclose(part.x, exec_part.x, rtol=1e-10)
35+
assert np.allclose(part.px, exec_part.px, rtol=1e-10)
36+
assert np.allclose(part.y, exec_part.y, rtol=1e-10)
37+
assert np.allclose(part.py, exec_part.py, rtol=1e-10)
38+
assert np.allclose(part.zeta, exec_part.zeta, rtol=1e-10)
39+
assert np.allclose(part.delta, exec_part.delta, rtol=1e-10)
40+
print("Particles match!")
41+
file_in.unlink()
42+
file_out.unlink()

pyproject.toml

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
[tool.poetry]
77
name = "xboinc"
8-
version = "0.1.5"
8+
version = "0.1.6"
99
description = "Xsuite BOINC interface"
1010
homepage = "https://github.com/xsuite/xboinc"
1111
repository = "https://github.com/xsuite/xboinc"
@@ -22,12 +22,12 @@ include = [ "LICENSE", "NOTICE" ]
2222
[tool.poetry.dependencies]
2323
python = '>=3.8'
2424
numpy = '>=1.0'
25-
xobjects = '==0.2.8'
26-
xdeps = '==0.4.2'
27-
xpart = '==0.15.3'
28-
xtrack = '==0.42.0'
29-
xfields = '==0.13.1'
30-
xcoll = '==0.2.5'
25+
xobjects = '==0.2.10'
26+
xdeps = '==0.5.2'
27+
xpart = '==0.16.3'
28+
xtrack = '==0.48.1'
29+
xfields = '==0.15.0'
30+
xcoll = '==0.2.7'
3131

3232
[tool.poetry.dev-dependencies]
3333
pytest = ">7"

tests/test_00_version.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313

1414
def test_version():
15-
assert __version__ == '0.1.5'
15+
assert __version__ == '0.1.6'
1616

1717

1818
def test_sim_ver():
@@ -25,12 +25,12 @@ def test_sim_ver():
2525

2626
def test_xsuite_versions():
2727
expected_version = {
28-
'xobjects' : '0.2.8',
29-
'xdeps' : '0.4.2',
30-
'xpart' : '0.15.3',
31-
'xtrack' : '0.42.0',
32-
'xfields' : '0.13.1',
33-
'xcoll' : '0.2.5',
28+
'xobjects' : '0.2.10',
29+
'xdeps' : '0.5.2',
30+
'xpart' : '0.16.3',
31+
'xtrack' : '0.48.1',
32+
'xfields' : '0.15.0',
33+
'xcoll' : '0.2.7',
3434
}
3535
current_version = {}
3636

tests/test_01_compilation_and_running.py

Lines changed: 28 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@
1818

1919
line_file = xb._pkg_root.parent / 'tests' / 'data' / 'sequence_lhc_run3_b1.json'
2020
num_turns = 1000
21+
input_filename = 'xboinc_input.bin'
22+
output_filename = 'sim_state_out.bin'
23+
checkpoint_filename = 'checkpoint.bin'
2124

2225

2326
def test_compilation():
@@ -48,13 +51,13 @@ def test_generate_input():
4851
xb._skip_xsuite_version_check = True
4952
line, part = _make_input()
5053
xb.SimConfig.build(line=line, particles=part, num_turns=num_turns, checkpoint_every=10,
51-
filename='xboinc_input.bin')
52-
input_file = Path.cwd() / "xboinc_input.bin"
54+
filename=input_filename)
55+
input_file = Path.cwd() / input_filename
5356
assert input_file.exists()
5457
xb._skip_xsuite_version_check = False
5558

5659

57-
def test_track():
60+
def test_track(request):
5861
xb._skip_xsuite_version_check = True
5962
# If no executable is present, make one
6063
exec_file = list(Path.cwd().glob(f'xboinc_{xb.app_version}-*'))
@@ -64,19 +67,22 @@ def test_track():
6467
exec_file = exec_file[0]
6568

6669
# If no input file is present, make one
67-
input_file = Path.cwd() / 'xboinc_input.bin'
70+
input_file = Path.cwd() / input_filename
6871
if not input_file.exists():
6972
test_generate_input()
7073

7174
# run xboinc tracker
7275
t1 = time.time()
7376
cmd = subprocess.run([exec_file])
74-
print(round(time.time() - t1, 1))
77+
calculation_time = round(time.time() - t1, 1)
78+
request.config.cache.set('calculation_time', calculation_time)
7579
if cmd.returncode != 0:
7680
raise RuntimeError(f"Tracking failed.")
81+
else:
82+
print(f"Tracking done in {calculation_time}s.")
7783

7884
# Read output
79-
output_file = Path.cwd() / 'sim_state_out.bin'
85+
output_file = Path.cwd() / output_filename
8086
assert output_file.exists()
8187
sim_state = xb.SimState.from_binary(output_file)
8288

@@ -93,11 +99,11 @@ def test_track():
9399
assert not np.allclose(part_xboinc.py, part_xboinc.py[0], rtol=1e-4, atol=0)
94100

95101
# Rename file for comparison in next test
96-
output_file.rename(output_file.parent / f'{output_file.name}_2')
102+
output_file.rename(output_file.parent / f"{output_filename}_2")
97103
xb._skip_xsuite_version_check = False
98104

99105

100-
def test_checkpoint():
106+
def test_checkpoint(request):
101107
xb._skip_xsuite_version_check = True
102108
# If no executable is present, make one
103109
exec_file = list(Path.cwd().glob(f'xboinc_{xb.app_version}-*'))
@@ -107,25 +113,28 @@ def test_checkpoint():
107113
exec_file = exec_file[0]
108114

109115
# If no input file is present, make one
110-
input_file = Path.cwd() / 'xboinc_input.bin'
116+
input_file = Path.cwd() / input_filename
111117
if not input_file.exists():
112118
test_generate_input()
113119

114120
# If previous output file not present, we need to regenerate it (to be able to compare)
115-
output_file = Path.cwd() / 'sim_state_out.bin_2'
121+
output_file = Path.cwd() / f"{output_filename}_2"
116122
if not output_file.exists():
117123
test_track()
118124

119125
# run xboinc tracker and interrupt halfway
120126
interrupted = False
121-
timeout = 25
127+
timeout = 0.6*request.config.cache.get('calculation_time', 25)
122128
print(f"Will interrupt after {timeout}s.")
129+
t1 = time.time()
130+
calculation_time = round(time.time() - t1, 1)
123131
try:
124132
cmd = subprocess.run(exec_file, timeout=timeout)
125133
except subprocess.TimeoutExpired:
126134
interrupted = True
127-
print("Interrupted calculation. Now trying to continue.")
128-
checkpoint_file = Path.cwd() / 'checkpoint.bin'
135+
t2 = time.time()
136+
print(f"Interrupted calculation after {round(t2 - t1, 1)}s. Now trying to continue.")
137+
checkpoint_file = Path.cwd() / checkpoint_filename
129138
assert checkpoint_file.exists()
130139
if not interrupted:
131140
raise ValueError("Timeout was too short. Adapt the test 'test_checkpoint'.")
@@ -134,18 +143,21 @@ def test_checkpoint():
134143
cmd = subprocess.run(exec_file)
135144
if cmd.returncode != 0:
136145
raise RuntimeError(f"Tracking failed.")
146+
else:
147+
t3 = time.time()
148+
print(f"Continued tracking done in {round(t3 - t2, 1)}s (total tracking time {round(t3 - t1, 1)}s).")
137149

138150
# Compare file to previous result
139-
output_file = Path.cwd() / 'sim_state_out.bin'
151+
output_file = Path.cwd() / output_filename
140152
assert output_file.exists()
141-
assert filecmp.cmp(output_file, output_file.parent / f'{output_file.name}_2', shallow=False)
153+
assert filecmp.cmp(output_file, output_file.parent / f"{output_file.name}_2", shallow=False)
142154
xb._skip_xsuite_version_check = False
143155

144156

145157
def test_vs_xtrack():
146158
xb._skip_xsuite_version_check = True
147159
# If no output is present, make one
148-
output_file = Path.cwd() / 'sim_state_out.bin_2'
160+
output_file = Path.cwd() / f"{output_filename}_2"
149161
if not output_file.exists():
150162
test_track()
151163
sim_state = xb.SimState.from_binary(output_file)

tests/test_02_user.py

Lines changed: 49 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -8,30 +8,59 @@
88
import pytest
99

1010
import xboinc as xb
11+
from xboinc.user import user_data_file, get_directory, get_domain, get_user_data
12+
from xboinc.server import server_account, dropdir, fs_exists
13+
from xboinc.server.paths import _test_afs, _test_eos
1114

15+
register_file = dropdir / f"register_{server_account}.json"
16+
deregister_file = dropdir / f"deregister_{server_account}.json"
17+
register_file_dev = dropdir / f"dev_register_{server_account}.json"
18+
deregister_file_dev = dropdir / f"dev_deregister_{server_account}.json"
1219

13-
user = 'sixtadm'
14-
folder_afs = Path('/afs/cern.ch/user/s/sixtadm/public/test_xboinc').resolve()
15-
folder_eos = Path('/afs/cern.ch/user/s/sixtadm/eos_sixtadm/test_xboinc').resolve()
16-
user_data_file = xb._pkg_root / 'user_data.json'
1720

18-
19-
def test_remove():
20-
xb.user.remove_user(user)
21-
with user_data_file.open('r') as fid:
21+
def test_register():
22+
xb.register(server_account, _test_afs)
23+
assert get_directory(server_account) == _test_afs
24+
assert (get_directory(server_account) / 'input').exists()
25+
assert (get_directory(server_account) / 'output').exists()
26+
assert (get_directory(server_account) / 'input_dev').exists()
27+
assert (get_directory(server_account) / 'output_dev').exists()
28+
assert get_domain(server_account) == 'afs'
29+
assert get_user_data(server_account)['directory'] == _test_afs.as_posix()
30+
assert get_user_data(server_account)['domain'] == 'afs'
31+
assert fs_exists(register_file)
32+
assert not fs_exists(deregister_file)
33+
with register_file.open('r') as fid:
2234
userdict = json.load(fid)
23-
assert user not in userdict.keys()
35+
assert userdict['user'] == server_account
36+
assert userdict['directory'] == _test_afs.as_posix()
37+
assert userdict['domain'] == 'afs'
38+
assert fs_exists(register_file_dev)
39+
assert not fs_exists(deregister_file_dev)
40+
with register_file_dev.open('r') as fid:
41+
userdict = json.load(fid)
42+
assert userdict['user'] == server_account
43+
assert userdict['directory'] == _test_afs.as_posix()
44+
assert userdict['domain'] == 'afs'
2445

46+
with pytest.raises(NotImplementedError):
47+
xb.register(server_account, _test_eos)
2548

26-
def test_register():
27-
xb.register(user, folder_afs)
28-
assert xb.user.get_folder(user) == folder_afs
29-
assert (xb.user.get_folder(user) / 'input').exists()
30-
assert (xb.user.get_folder(user) / 'output').exists()
31-
assert xb.user.get_domain(user) == 'afs'
32-
assert xb.user.get_user_data(user)['folder'] == folder_afs.as_posix()
33-
assert xb.user.get_user_data(user)['domain'] == 'afs'
34-
assert xb.server.eos.eos_exists(xb.server.paths.dropdir / f"register_{user}.json")
3549

36-
with pytest.raises(NotImplementedError):
37-
xb.register(user, folder_eos)
50+
def test_deregister():
51+
xb.deregister(server_account)
52+
with user_data_file.open('r') as fid:
53+
userdict = json.load(fid)
54+
assert server_account not in userdict.keys()
55+
with pytest.raises(ValueError):
56+
get_user_data(server_account)
57+
assert not fs_exists(register_file)
58+
assert not fs_exists(register_file_dev)
59+
assert fs_exists(deregister_file)
60+
with deregister_file.open('r') as fid:
61+
userdict = json.load(fid)
62+
assert userdict['user'] == server_account
63+
assert fs_exists(deregister_file_dev)
64+
with deregister_file_dev.open('r') as fid:
65+
userdict = json.load(fid)
66+
assert userdict['user'] == server_account

0 commit comments

Comments
 (0)