#pragma once #include #include #include #include template class SignedDistanceBoundary { private: const descriptor::Cuboid _cuboid; const std::size_t _count; SharedVector _boundary; SharedVector _fluid; SharedVector _solid; SharedVector _distance; SharedVector _correction; SharedVector _factor; SharedVector _missing; void set(std::size_t index, std::size_t iCell, pop_index_t iPop, S dist) { pop_index_t jPop = descriptor::opposite(iPop); const std::size_t jPopCell = descriptor::neighbor(_cuboid, iCell, jPop); const std::size_t iPopCell = descriptor::neighbor(_cuboid, iCell, iPop); _boundary[index] = iCell; _solid[index] = jPopCell; _distance[index] = dist; _correction[index] = 0; _missing[index] = iPop; T q = dist / descriptor::velocity_length(iPop); if (q > 0.5) { _fluid[index] = iCell; _factor[index] = 1 / (2*q); } else { _fluid[index] = iPopCell; _factor[index] = 2*q; } } void syncDeviceFromHost() { _boundary.syncDeviceFromHost(); _fluid.syncDeviceFromHost(); _solid.syncDeviceFromHost(); _distance.syncDeviceFromHost(); _correction.syncDeviceFromHost(); _factor.syncDeviceFromHost(); _missing.syncDeviceFromHost(); } public: SignedDistanceBoundary(Lattice&, CellMaterials& materials, SDF geometry, int bulk, int solid): _cuboid(materials.cuboid()), _count(materials.get_link_count(bulk, solid)), _boundary(_count), _fluid(_count), _solid(_count), _distance(_count), _correction(_count), _factor(_count), _missing(_count) { std::size_t index = 0; materials.for_links(bulk, solid, [&](std::size_t iCell, pop_index_t iPop) { auto p = gidInverseSmooth(_cuboid, iCell); auto direction = normalize(descriptor::velocity(iPop)); float length = descriptor::velocity_length(iPop); float distance = approximateDistance(geometry, p, direction, 0, length); if (distance == 0.f || distance > length) { std::cout << "Bogus distance d=" << distance << " at cell " << iCell << " in direction " << std::to_string(iPop) << std::endl; } set(index++, iCell, descriptor::opposite(iPop), distance); }); syncDeviceFromHost(); } template void setVelocity(VELOCITY field) { for (std::size_t index=0; index < _count; ++index) { pop_index_t jPop = descriptor::opposite(_missing[index]); auto direction = normalize(descriptor::velocity(jPop)); float length = descriptor::velocity_length(jPop); auto p = descriptor::gidInverseSmooth(_cuboid, _boundary[index]); auto u_w = field(p + _distance[index] * direction); _correction[index] = 2*3*descriptor::weight(jPop) * dot(u_w, descriptor::velocity(jPop)); if (_distance[index] / length > 0.5) { _correction[index] *= _factor[index]; } } _correction.syncDeviceFromHost(); } std::size_t getCount() const { return _count; } BouzidiConfig getConfig() { return BouzidiConfig{ _boundary.device(), _solid.device(), _fluid.device(), _factor.device(), _correction.device(), _missing.device() }; } }; template SignedDistanceBoundary(Lattice&, CellMaterials&, SDF, int, int) -> SignedDistanceBoundary;