Files
mfem/linalg/particlevector.cpp
T

314 lines
8.4 KiB
C++

// Copyright (c) 2010-2025, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.
#include "particlevector.hpp"
namespace mfem
{
void ParticleVector::GrowSize(int min_num_vectors, bool keep_data)
{
const int nsize = std::max(min_num_vectors*vdim, 2 * data.Capacity());
Memory<real_t> p(nsize, data.GetMemoryType());
if (keep_data) { p.CopyFrom(data, size); }
p.UseDevice(data.UseDevice());
data.Delete();
data = p;
}
ParticleVector::ParticleVector(int vdim_, Ordering::Type ordering_)
: ParticleVector(vdim_, ordering_, 0) { }
ParticleVector::ParticleVector(int vdim_, Ordering::Type ordering_,
int num_nodes)
: Vector(num_nodes*vdim_), vdim(vdim_), ordering(ordering_)
{
Vector::operator=(0.0);
}
ParticleVector::ParticleVector(int vdim_, Ordering::Type ordering_,
const Vector &vec)
: Vector(vec), vdim(vdim_), ordering(ordering_)
{
MFEM_ASSERT(vec.Size() % vdim == 0,
"Incompatible Vector size of " << vec.Size() << " given vdim " << vdim);
}
void ParticleVector::GetValues(int i, Vector &nvals) const
{
nvals.SetSize(vdim);
if (ordering == Ordering::byNODES)
{
int nv = GetNumParticles();
for (int c = 0; c < vdim; c++)
{
nvals[c] = Vector::operator[](i+nv*c);
}
}
else
{
for (int c = 0; c < vdim; c++)
{
nvals[c] = Vector::operator[](c+vdim*i);
}
}
}
void ParticleVector::GetValuesRef(int i, Vector &nref)
{
MFEM_ASSERT(ordering == Ordering::byVDIM,
"GetValuesRef only valid when ordering byVDIM.");
nref.MakeRef(*this, i*vdim, vdim);
}
void ParticleVector::GetComponents(int vd, Vector &comp)
{
int vdim_temp = vdim;
// For byNODES: Treat each component as a vector temporarily
// For byVDIM: Treat each vector as a component temporarily
vdim = GetNumParticles();
ordering = ordering == Ordering::byNODES ? Ordering::byVDIM :
Ordering::byNODES;
GetValues(vd, comp);
// Reset ordering back to original
ordering = ordering == Ordering::byNODES ? Ordering::byVDIM :
Ordering::byNODES;
vdim = vdim_temp;
}
void ParticleVector::GetComponentsRef(int vd, Vector &nref)
{
MFEM_ASSERT(ordering == Ordering::byNODES,
"GetComponentsRef only valid when ordering byNODES.");
nref.MakeRef(*this, vd*GetNumParticles(), GetNumParticles());
}
void ParticleVector::SetValues(int i, const Vector &nvals)
{
if (ordering == Ordering::byNODES)
{
int nv = GetNumParticles();
for (int c = 0; c < vdim; c++)
{
Vector::operator[](i + c*nv) = nvals[c];
}
}
else
{
for (int c = 0; c < vdim; c++)
{
Vector::operator[](c + i*vdim) = nvals[c];
}
}
}
void ParticleVector::SetComponents(int vd, const Vector &comp)
{
int vdim_temp = vdim;
// For byNODES: Treat each component as a vector temporarily
// For byVDIM: Treat each vector as a component temporarily
vdim = GetNumParticles();
ordering = ordering == Ordering::byNODES ? Ordering::byVDIM :
Ordering::byNODES;
SetValues(vd, comp);
// Reset ordering back to original
ordering = ordering == Ordering::byNODES ? Ordering::byVDIM :
Ordering::byNODES;
vdim = vdim_temp;
}
real_t& ParticleVector::operator()(int i, int comp)
{
MFEM_ASSERT(i < GetNumParticles(),
"Particle index " << i <<
" is invalid for number of particles " << GetNumParticles());
MFEM_ASSERT(comp < vdim,
"Component index " << comp <<
" is invalid for vector dimension " << vdim);
if (ordering == Ordering::byNODES)
{
return Vector::operator[](i + comp*GetNumParticles());
}
else
{
return Vector::operator[](comp + i*vdim);
}
}
const real_t& ParticleVector::operator()(int i, int comp) const
{
MFEM_ASSERT(i < GetNumParticles(),
"Particle index " << i <<
" is invalid for number of particles " << GetNumParticles());
MFEM_ASSERT(comp < vdim,
"Component index " << comp <<
" is invalid for vector dimension " << vdim);
if (ordering == Ordering::byNODES)
{
return Vector::operator[](i + comp*GetNumParticles());
}
else
{
return Vector::operator[](comp + i*vdim);
}
}
void ParticleVector::DeleteParticles(const Array<int> &indices)
{
if (indices.Size() == 0) { return; }
// Convert list index array of "ldofs" to "vdofs"
Array<int> v_list;
v_list.Reserve(indices.Size()*vdim);
MFEM_VERIFY(indices.Max() < GetNumParticles(),
"Particle index " << indices.Max() <<
" is out-of-range for number of particles " <<
GetNumParticles());
if (ordering == Ordering::byNODES)
{
for (int l = 0; l < indices.Size(); l++)
{
for (int vd = 0; vd < vdim; vd++)
{
v_list.Append(Ordering::Map<Ordering::byNODES>(GetNumParticles(),
vdim,
indices[l], vd));
}
}
}
else
{
for (int l = 0; l < indices.Size(); l++)
{
for (int vd = 0; vd < vdim; vd++)
{
v_list.Append(Ordering::Map<Ordering::byVDIM>(GetNumParticles(),
vdim,
indices[l],
vd));
}
}
}
Vector::DeleteAt(v_list);
}
void ParticleVector::SetVDim(int vdim_, bool keep_data)
{
if (!keep_data)
{
int num_particles = GetNumParticles();
vdim = vdim_;
Vector::SetSize(num_particles*vdim_);
return;
}
// Reorder/shift existing entries
// For byNODES: Treat each component as a vector temporarily
// For byVDIM: Treat each vector as a component temporarily
vdim = GetNumParticles();
ordering = ordering == Ordering::byNODES ? Ordering::byVDIM :
Ordering::byNODES;
SetNumParticles(vdim_, keep_data);
// Reset ordering back to original
ordering = ordering == Ordering::byNODES ? Ordering::byVDIM :
Ordering::byNODES;
vdim = vdim_;
}
void ParticleVector::SetOrdering(Ordering::Type ordering_, bool keep_data)
{
if (keep_data)
{
Ordering::Reorder(*this, vdim, ordering, ordering_);
}
ordering = ordering_;
}
void ParticleVector::SetNumParticles(int num_vectors, bool keep_data)
{
int old_nv = GetNumParticles();
if (num_vectors == old_nv)
{
return;
}
// If resizing larger...
if (num_vectors > old_nv)
{
// Increase capacity if needed
if (num_vectors*vdim > Vector::Capacity())
{
GrowSize(num_vectors, keep_data);
}
// Set larger new size
Vector::SetSize(num_vectors*vdim);
if (!keep_data) { return; }
if (ordering == Ordering::byNODES)
{
// Shift entries for byNODES
for (int c = vdim-1; c > 0; c--)
{
for (int i = old_nv-1; i >= 0; i--)
{
Vector::operator[](i+c*num_vectors) = Vector::operator[](i+c*old_nv);
}
}
// Zero-out data now associated with new Vectors
for (int c = 0; c < vdim; c++)
{
for (int i = old_nv; i < num_vectors; i++)
{
Vector::operator[](i+c*num_vectors) = 0.0;
}
}
}
else // byVDIM
{
for (int i = old_nv*vdim; i < num_vectors*vdim; i++)
{
data[i] = 0.0;
}
}
}
else // Else just remove the trailing vector data
{
if (!keep_data) { Vector::SetSize(num_vectors*vdim); return; }
Array<int> rm_indices(old_nv-num_vectors);
for (int i = 0; i < rm_indices.Size(); i++)
{
rm_indices[i] = old_nv - rm_indices.Size() + i;
}
DeleteParticles(rm_indices);
}
}
} // namespace mfem