Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Obtain exact time (real) when particles hit boundaries + test #4695

Merged
merged 42 commits into from
Feb 17, 2024
Merged
Show file tree
Hide file tree
Changes from 34 commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
c1d92c1
adding the time
EyaDammak Feb 13, 2024
2e9d233
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Feb 13, 2024
2d818e3
Update particle_containers.py
EyaDammak Feb 13, 2024
1f76a5e
Update ParticleBoundaryBuffer.cpp
EyaDammak Feb 13, 2024
cf6c5f3
Update PICMI_inputs_rz.py
EyaDammak Feb 13, 2024
1e67dc1
Update PICMI_inputs_rz.py
EyaDammak Feb 13, 2024
83cfee8
Update particle_containers.py
EyaDammak Feb 13, 2024
0de37e3
Update ParticleBoundaryBuffer.cpp
EyaDammak Feb 13, 2024
43130f9
Update ParticleBoundaryBuffer.cpp
EyaDammak Feb 13, 2024
ae0d279
Update ParticleBoundaryBuffer.cpp
EyaDammak Feb 13, 2024
bd52df6
fix issue
EyaDammak Feb 13, 2024
29ab214
fix issue
EyaDammak Feb 13, 2024
67b6676
issue fixed
EyaDammak Feb 13, 2024
c4a98f0
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Feb 13, 2024
3903344
Update ParticleBoundaryBuffer.cpp
EyaDammak Feb 13, 2024
649d42b
Update ParticleBoundaryBuffer.cpp
EyaDammak Feb 13, 2024
ccd5f9b
Update ParticleBoundaryBuffer.cpp
EyaDammak Feb 13, 2024
9688d42
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Feb 13, 2024
0261afb
Update ParticleBoundaryBuffer.cpp
EyaDammak Feb 13, 2024
149cce8
Update ParticleBoundaryBuffer.cpp
EyaDammak Feb 13, 2024
0d1b5e9
Update ParticleBoundaryBuffer.cpp
EyaDammak Feb 13, 2024
3baacd9
Update ParticleBoundaryBuffer.cpp
EyaDammak Feb 13, 2024
95657bd
Update ParticleBoundaryBuffer.cpp
EyaDammak Feb 14, 2024
2677c8a
Update analysis_rz.py
EyaDammak Feb 14, 2024
629f813
Update analysis_rz_filter.py
EyaDammak Feb 14, 2024
b056c02
Update analysis.py
EyaDammak Feb 14, 2024
341d44b
Update PICMI_inputs_scrape.py
EyaDammak Feb 14, 2024
00e8b64
Update PICMI_inputs_reflection.py
EyaDammak Feb 14, 2024
1eee448
Update particle_containers.py
EyaDammak Feb 15, 2024
b68b880
Update PICMI_inputs_reflection.py
EyaDammak Feb 15, 2024
c9f505d
Update PICMI_inputs_scrape.py
EyaDammak Feb 15, 2024
9fe74ca
Update ParticleBoundaryBuffer.cpp
EyaDammak Feb 15, 2024
f7396f3
Update ParticleBoundaryBuffer.cpp
EyaDammak Feb 15, 2024
36c9faf
Merge branch 'development' into exact_time
EyaDammak Feb 16, 2024
68cdfed
Update ParticleBoundaryBuffer.cpp
EyaDammak Feb 16, 2024
f2a10f4
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Feb 16, 2024
63dfd5d
Update ParticleBoundaryBuffer.cpp
EyaDammak Feb 16, 2024
1268500
Update ParticleBoundaryBuffer.cpp
EyaDammak Feb 16, 2024
3584bfb
Update ParticleBoundaryBuffer.cpp
EyaDammak Feb 16, 2024
a845cca
Update Source/Particles/ParticleBoundaryBuffer.cpp
EyaDammak Feb 16, 2024
449241e
Update Source/Particles/ParticleBoundaryBuffer.cpp
EyaDammak Feb 16, 2024
914686b
Update ParticleBoundaryBuffer.cpp
EyaDammak Feb 16, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions Docs/source/usage/parameters.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2752,8 +2752,10 @@ The data collected at each boundary is written out to a subdirectory of the diag
By default, all of the collected particle data is written out at the end of the simulation. Optionally, the ``<diag_name>.intervals`` parameter can be given to specify writing out the data more often.
This can be important if a large number of particles are lost, avoiding filling up memory with the accumulated lost particle data.

In addition to their usual attributes, the saved particles have an integer attribute ``timestamp``, which
indicates the PIC iteration at which each particle was absorbed at the boundary.
In addition to their usual attributes, the saved particles have an integer attribute ``step_scraped``, which
indicates the PIC iteration at which each particle was absorbed at the boundary,
and a real attribute ``time_scraped``, which indicates the exact time calculated when each
particle hits the EB.

``BoundaryScrapingDiagnostics`` can be used with ``<diag_name>.<species>.random_fraction``, ``<diag_name>.<species>.uniform_stride``, and ``<diag_name>.<species>.plot_filter_function``, which have the same behavior as for ``FullDiagnostics``. For ``BoundaryScrapingDiagnostics``, these filters are applied at the time the data is written to file. An implication of this is that more particles may initially be accumulated in memory than are ultimately written. ``t`` in ``plot_filter_function`` refers to the time the diagnostic is written rather than the time the particle crossed the boundary.

Expand Down
17 changes: 13 additions & 4 deletions Examples/Tests/point_of_contact_EB/analysis.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,26 +26,35 @@
ts_scraping = OpenPMDTimeSeries('./diags/diag2/particles_at_eb/')

it=ts_scraping.iterations
x,y,z=ts_scraping.get_particle( ['x','y','z'], species='electron', iteration=it )
step_scraped, time_scraped, x, y, z=ts_scraping.get_particle( ['stepScraped','timeScraped','x','y','z'], species='electron', iteration=it )
time_scraped_reduced=time_scraped[0]*1e10

# Analytical results calculated
x_analytic=-0.1983
y_analytic=0.02584
z_analytic=0.0000

#result obtained by analysis of simulations
step=3
time_reduced=3.58

print('NUMERICAL coordinates of the point of contact:')
print('x=%5.4f, y=%5.4f, z=%5.4f' % (x[0], y[0], z[0]))
print('step_scraped=%d, time_stamp=%5.4f e-10, x=%5.4f, y=%5.4f, z=%5.4f' % (step_scraped[0],time_reduced,x[0], y[0], z[0]))
print('\n')
print('ANALYTICAL coordinates of the point of contact:')
print('x=%5.4f, y=%5.4f, z=%5.4f' % (x_analytic, y_analytic, z_analytic))
print('step_scraped=%d, time_stamp=%5.4f e-10, x=%5.4f, y=%5.4f, z=%5.4f' % (step, time_reduced, x_analytic, y_analytic, z_analytic))

tolerance=0.001
tolerance_t=0.003
print("tolerance = "+ str(tolerance *100) + '%')
print("tolerance for the time = "+ str(tolerance_t *100) + '%')

diff_step=np.abs((step_scraped[0]-step)/step)
diff_time=np.abs((time_scraped_reduced-time_reduced)/time_reduced)
diff_x=np.abs((x[0]-x_analytic)/x_analytic)
diff_y=np.abs((y[0]-y_analytic)/y_analytic)

print("percentage error for x = %5.4f %%" %(diff_x *100))
print("percentage error for y = %5.4f %%" %(diff_y *100))

assert (diff_x < tolerance) and (diff_y < tolerance) and (np.abs(z[0]) < 1e-8) , 'Test point_of_contact did not pass'
assert (diff_x < tolerance) and (diff_y < tolerance) and (np.abs(z[0]) < 1e-8) and (diff_step < 1e-8) and (diff_time < tolerance_t) , 'Test point_of_contact did not pass'
4 changes: 2 additions & 2 deletions Examples/Tests/scraping/analysis_rz.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,8 @@ def n_remaining_particles( iteration ):
w, = ts_full.get_particle(['w'], iteration=iteration)
return len(w)
def n_scraped_particles( iteration ):
timestamp = ts_scraping.get_particle( ['timestamp'], iteration=ts_scraping.iterations[0] )
return (timestamp <= iteration).sum()
step_scraped = ts_scraping.get_particle( ['stepScraped'], iteration=ts_scraping.iterations[0] )
return (step_scraped <= iteration).sum()
n_remaining = np.array([ n_remaining_particles(iteration) for iteration in ts_full.iterations ])
n_scraped = np.array([ n_scraped_particles(iteration) for iteration in ts_full.iterations ])
n_total = n_remaining[0]
Expand Down
4 changes: 2 additions & 2 deletions Examples/Tests/scraping/analysis_rz_filter.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ def n_remaining_particles( iteration ):
w, = ts_full.get_particle(['w'], iteration=iteration)
return len(w)
def n_scraped_particles( iteration ):
timestamp = ts_scraping.get_particle( ['timestamp'], iteration=ts_scraping.iterations[0] )
return (timestamp <= iteration).sum()
step_scraped = ts_scraping.get_particle( ['stepScraped'], iteration=ts_scraping.iterations[0] )
return (step_scraped <= iteration).sum()
def n_scraped_z_leq_zero( iteration ):
z_pos, = ts_scraping.get_particle( ['z'], iteration=ts_scraping.iterations[0] )
return (z_pos <= 0).sum()
Expand Down
24 changes: 13 additions & 11 deletions Python/pywarpx/particle_containers.py
Original file line number Diff line number Diff line change
Expand Up @@ -772,9 +772,9 @@ def get_particle_boundary_buffer(self, species_name, boundary, comp_name, level)
form x/y/z_hi/lo or eb.

comp_name : str
The component of the array data that will be returned. If
"step_scraped" the special attribute holding the timestep at
which a particle was scraped will be returned.
The component of the array data that will be returned.
"x", "y", "z", "ux", "uy", "uz", "w"
"step_scraped","time_scraped", "nx", "ny", "nz"

level : int
Which AMR level to retrieve scraped particle data from.
Expand All @@ -785,18 +785,20 @@ def get_particle_boundary_buffer(self, species_name, boundary, comp_name, level)
species_name, self._get_boundary_number(boundary)
)
data_array = []
if comp_name == 'step_scraped':
# the step scraped is always the final integer component
comp_idx = part_container.num_int_comps - 1
#loop over the real attributes
if comp_name in part_container.real_comp_names:
comp_idx = part_container.real_comp_names[comp_name]
for ii, pti in enumerate(libwarpx.libwarpx_so.BoundaryBufferParIter(part_container, level)):
soa = pti.soa()
data_array.append(xp.array(soa.get_real_data(comp_idx), copy=False))
#loop over the integer attributes
elif comp_name in part_container.int_comp_names:
comp_idx = part_container.int_comp_names[comp_name]
for ii, pti in enumerate(libwarpx.libwarpx_so.BoundaryBufferParIter(part_container, level)):
soa = pti.soa()
data_array.append(xp.array(soa.get_int_data(comp_idx), copy=False))
else:
container_wrapper = ParticleContainerWrapper(species_name)
comp_idx = container_wrapper.particle_container.get_comp_index(comp_name)
for ii, pti in enumerate(libwarpx.libwarpx_so.BoundaryBufferParIter(part_container, level)):
soa = pti.soa()
data_array.append(xp.array(soa.get_real_data(comp_idx), copy=False))
raise RuntimeError('Name %s not found' %comp_name)
return data_array


Expand Down
2 changes: 1 addition & 1 deletion Source/Diagnostics/BTDiagnostics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1299,7 +1299,7 @@ BTDiagnostics::InterleaveBufferAndSnapshotHeader ( std::string buffer_Header_pat
BTDPlotfileHeaderImpl buffer_HeaderImpl(buffer_Header_path);
buffer_HeaderImpl.ReadHeaderData();

// Update timestamp of snapshot with recently flushed buffer
// Update step_scraped of snapshot with recently flushed buffer
snapshot_HeaderImpl.set_time( buffer_HeaderImpl.time() );
snapshot_HeaderImpl.set_timestep( buffer_HeaderImpl.timestep() );

Expand Down
30 changes: 18 additions & 12 deletions Source/Particles/ParticleBoundaryBuffer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,6 @@ struct FindEmbeddedBoundaryIntersection {
dst.m_runtime_idata[j][dst_i] = src.m_runtime_idata[j][src_i];
}

// Also record the integer timestep on the destination
dst.m_runtime_idata[m_index][dst_i] = m_step;

// Modify the position of the destination particle:
// Move it to the point of intersection with the embedded boundary
// (which is found by using a bisection algorithm)
Expand All @@ -90,7 +87,6 @@ struct FindEmbeddedBoundaryIntersection {
amrex::GpuArray<amrex::Real, AMREX_SPACEDIM> plo = m_plo;

// Bisection algorithm to find the point where phi(x,y,z)=0 (i.e. on the embedded boundary)

amrex::Real dt_fraction = amrex::bisect( 0.0, 1.0,
[=] (amrex::Real dt_frac) {
int i, j, k;
Expand All @@ -102,6 +98,10 @@ struct FindEmbeddedBoundaryIntersection {
return phi_value;
} );

// Also record the real time on the destination
dst.m_runtime_idata[m_index][dst_i] = m_step;
dst.m_runtime_rdata[m_index][dst_i] = m_step*m_dt + (1- dt_fraction)*m_dt;

// Now that dt_fraction has be obtained (with bisect)
// Save the corresponding position of the particle at the boundary
amrex::ParticleReal x_temp=xp, y_temp=yp, z_temp=zp;
Expand Down Expand Up @@ -131,6 +131,7 @@ struct FindEmbeddedBoundaryIntersection {
struct CopyAndTimestamp {
int m_index;
int m_step;
const amrex::Real m_dt;

template <typename DstData, typename SrcData>
AMREX_GPU_HOST_DEVICE
Expand All @@ -148,9 +149,11 @@ struct CopyAndTimestamp {
dst.m_runtime_idata[j][dst_i] = src.m_runtime_idata[j][src_i];
}
dst.m_runtime_idata[m_index][dst_i] = m_step;
dst.m_runtime_rdata[m_index][dst_i] = m_step*m_dt;
}
};


ParticleBoundaryBuffer::ParticleBoundaryBuffer ()
{
m_particle_containers.resize(numBoundaries());
Expand Down Expand Up @@ -328,7 +331,8 @@ void ParticleBoundaryBuffer::gatherParticles (MultiParticleContainer& mypc,
if (!buffer[i].isDefined())
{
buffer[i] = pc.make_alike<amrex::PinnedArenaAllocator>();
buffer[i].AddIntComp("timestamp", false);
buffer[i].AddIntComp("step_scraped", false);
buffer[i].AddRealComp("time_scraped", false);
}
auto& species_buffer = buffer[i];
for (int lev = 0; lev < pc.numLevels(); ++lev)
Expand Down Expand Up @@ -368,12 +372,14 @@ void ParticleBoundaryBuffer::gatherParticles (MultiParticleContainer& mypc,
}
{
WARPX_PROFILE("ParticleBoundaryBuffer::gatherParticles::filterAndTransform");
const int timestamp_index = ptile_buffer.NumRuntimeIntComps()-1;
auto& warpx = WarpX::GetInstance();
const auto dt = warpx.getdt(pti.GetLevel());
const int step_scraped_index = ptile_buffer.NumRuntimeIntComps()-1;
const int timestep = warpx_instance.getistep(0);

amrex::filterAndTransformParticles(ptile_buffer, ptile,
predicate,
CopyAndTimestamp{timestamp_index, timestep},
CopyAndTimestamp{step_scraped_index, timestep,dt},
0, dst_index);
}
}
Expand All @@ -393,7 +399,8 @@ void ParticleBoundaryBuffer::gatherParticles (MultiParticleContainer& mypc,
if (!buffer[i].isDefined())
{
buffer[i] = pc.make_alike<amrex::PinnedArenaAllocator>();
buffer[i].AddIntComp("timestamp", false);
buffer[i].AddIntComp("step_scraped", false);
buffer[i].AddRealComp("time_scraped", false);
}
auto& species_buffer = buffer[i];
for (int lev = 0; lev < pc.numLevels(); ++lev)
Expand Down Expand Up @@ -444,16 +451,15 @@ void ParticleBoundaryBuffer::gatherParticles (MultiParticleContainer& mypc,
WARPX_PROFILE("ParticleBoundaryBuffer::gatherParticles::resize_eb");
ptile_buffer.resize(dst_index + amrex::get<0>(reduce_data.value()));
}

const int timestamp_index = ptile_buffer.NumRuntimeIntComps()-1;
const int timestep = warpx_instance.getistep(0);
auto& warpx = WarpX::GetInstance();
const auto dt = warpx.getdt(pti.GetLevel());
const int step_scraped_index = ptile_buffer.NumRuntimeIntComps()-1;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

auto string_to_index_intcomp = buffer[i].getParticleiComps();
int step_scraped_index = string_to_index_intcomp.at('step_scraped');
auto string_to_index_realcomp = buffer[i].getParticleComps();
int time_scraped_index = string_to_index_realcomp.at('time_scraped');

const int step = warpx_instance.getistep(0);

{
WARPX_PROFILE("ParticleBoundaryBuffer::gatherParticles::filterTransformEB");
amrex::filterAndTransformParticles(ptile_buffer, ptile, predicate,
FindEmbeddedBoundaryIntersection{timestamp_index, timestep, dt, phiarr, dxi, plo}, 0, dst_index);
FindEmbeddedBoundaryIntersection{step_scraped_index, step, dt, phiarr, dxi, plo}, 0, dst_index);
}
}
}
Expand Down
13 changes: 13 additions & 0 deletions Source/Python/Particles/PinnedMemoryParticleContainer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,17 @@ void init_PinnedMemoryParticleContainer (py::module& m)
PinnedMemoryParticleContainer,
amrex::ParticleContainerPureSoA<PIdx::nattribs, 0, amrex::PinnedArenaAllocator>
> pmpc (m, "PinnedMemoryParticleContainer");
pmpc
.def_property_readonly("real_comp_names",
[](PinnedMemoryParticleContainer& pc)
{
return pc.getParticleComps();
}
)
.def_property_readonly("int_comp_names",
[](PinnedMemoryParticleContainer& pc)
{
return pc.getParticleiComps();
}
);
}
Loading