diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..8afcb10 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "runtime/extern/jsoncons"] + path = runtime/extern/jsoncons + url = https://github.com/danielaparker/jsoncons.git diff --git a/runtime/CMakeLists.txt b/runtime/CMakeLists.txt index 93086bd..d90423d 100644 --- a/runtime/CMakeLists.txt +++ b/runtime/CMakeLists.txt @@ -63,6 +63,11 @@ option(CUDA_KEEP_INTERMEDIATE_FILES OFF ) +option(WAR_OF_GALAXIES + "On to enable WarOfGalaxies" + OFF + ) + FIND_PACKAGE(CUDA REQUIRED) add_definitions(-std=c++11) @@ -278,6 +283,23 @@ if (USE_OPENGL) endif (USE_OPENGL) +if (WAR_OF_GALAXIES) + add_definitions(-DWAR_OF_GALAXIES) + add_definitions("-std=c++11") + include_directories(${CMAKE_SOURCE_DIR}/extern/jsoncons/include) + set (CCFILES ${CCFILES} + src/Galaxy.cpp + src/read_tipsy_file_parallel.cpp + src/WOGManager.cpp + ) + set (CUFILES ${CUFILES} + CUDAkernels/war_of_galaxies.cu + ) + if (USE_THRUST) + set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DTHRUST_DEBUG") + endif() +endif (WAR_OF_GALAXIES) + #The SSE support for the local tree walks if(WIN32) add_definitions( "/arch:SSE4") diff --git a/runtime/CUDAkernels/war_of_galaxies.cu b/runtime/CUDAkernels/war_of_galaxies.cu new file mode 100644 index 0000000..bb76a03 --- /dev/null +++ b/runtime/CUDAkernels/war_of_galaxies.cu @@ -0,0 +1,84 @@ +/* + * war_of_galaxies.cu + * + * Created on: Jun 14, 2016 + * Author: Bernd Doser + */ + +#ifdef USE_THRUST + +#include "bonsai.h" +#include "thrust_war_of_galaxies.h" +#include +#include +#include +#include + +/// Functor return true if position is out of sphere +struct OutOfSphereChecker +{ + OutOfSphereChecker(real deletion_radius_square) + : deletion_radius_square(deletion_radius_square) + {} + + __device__ + bool operator()(thrust::tuple const& t) const + { + real4 position = thrust::get<0>(t); + return position.x * position.x + position.y * position.y + position.z * position.z > deletion_radius_square + and thrust::get<2>(t) % 10 != 9; + } + + real deletion_radius_square; +}; + +/// Functor return true if modules is equal +struct EqualToModulus10 +{ + EqualToModulus10(int user_id) + : user_id(user_id) + {} + + __device__ + bool operator()(int i) const + { + return i % 10 == user_id; + } + + int user_id; +}; + +// Remove particles out of sphere +extern "C" void remove_particles(tree_structure &tree, + real deletion_radius_square, my_dev::dev_mem &user_particles, int number_of_users) +{ + thrust::device_ptr thrust_pos = thrust::device_pointer_cast(tree.bodies_pos.raw_p()); + thrust::device_ptr thrust_vel = thrust::device_pointer_cast(tree.bodies_vel.raw_p()); + thrust::device_ptr thrust_ids = thrust::device_pointer_cast(tree.bodies_ids.raw_p()); + thrust::device_ptr thrust_user_particles = thrust::device_pointer_cast(user_particles.raw_p()); + + try { + // auto is not working, compiler assume int + thrust::zip_iterator< thrust::tuple, thrust::device_ptr, thrust::device_ptr > > new_end = + thrust::remove_if( + thrust::device, + thrust::make_zip_iterator(thrust::make_tuple(thrust_pos, thrust_vel, thrust_ids)), + thrust::make_zip_iterator(thrust::make_tuple(thrust_pos + tree.n, thrust_vel + tree.n, thrust_ids + tree.n)), + OutOfSphereChecker(deletion_radius_square) + ); + + // Set new number of particles + tree.n = thrust::get<0>(new_end.get_iterator_tuple()) - thrust_pos; + + // Update user particles + for (int i(0); i != number_of_users; ++i) + thrust_user_particles[i] = thrust::count_if(thrust_ids, thrust_ids + tree.n, EqualToModulus10(i)); + } + catch(thrust::system_error &e) + { + std::cerr << "Error accessing vector element: " << e.what() << std::endl; + exit(-1); + } +} + +#endif diff --git a/runtime/extern/jsoncons b/runtime/extern/jsoncons new file mode 160000 index 0000000..3d8df17 --- /dev/null +++ b/runtime/extern/jsoncons @@ -0,0 +1 @@ +Subproject commit 3d8df17407420ad5d041d2fd9df24ee8be8c72f5 diff --git a/runtime/include/Galaxy.h b/runtime/include/Galaxy.h new file mode 100644 index 0000000..6d5d555 --- /dev/null +++ b/runtime/include/Galaxy.h @@ -0,0 +1,43 @@ +/* + * Galaxies.h + * + * Created on: Apr 12, 2016 + * Author: Bernd Doser + */ + +#pragma once + +#include +#include + +typedef unsigned long long ullong; + +/// One defined galaxy +struct Galaxy +{ + /// Center of mass + real4 getCenterOfMass() const; + + /// Center-of-mass Velocity + real4 getCenterOfMassVelocity() const; + + /// Move center of mass to origin (0,0,0) + void centering(); + + /// Remove center-of-mass velocity + void steady(); + + /// Move center of the galaxy + void translate(real4 w); + + /// Accelerate the galaxy + void accelerate(real4 w); + + std::vector pos; + std::vector vel; + std::vector ids; + + std::vector pos_dust; + std::vector vel_dust; + std::vector ids_dust; +}; diff --git a/runtime/include/WOGManager.h b/runtime/include/WOGManager.h new file mode 100644 index 0000000..a4bf0fc --- /dev/null +++ b/runtime/include/WOGManager.h @@ -0,0 +1,111 @@ +/* + * WOGManager.h + * + * Created on: May 11, 2016 + * Author: Bernd Doser + */ + +#pragma once + +#include "Galaxy.h" +#include "octree.h" +#include "jsoncons/json.hpp" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct sockaddr_in; + +/** + * War of Galaxies (WOG) + * - Store galaxy type which can be released + * - Control interconnection via UNIX socket + * - Add and remove particles to running simulation + */ +class WOGManager +{ + public: + + /// Constructor opening sockets and reading input galaxies + WOGManager(octree *tree, std::string const& path, int port, int window_width, int window_height, real fovy, + real farZ, real camera_distance, real deletion_radius_factor); + + /// Constructor closing the sockets + ~WOGManager(); + + /// Execute a client request + void execute(); + + /// Must be called by glutReshapeFunc + void reshape(int width, int height); + + /// Return camera distance + real get_camera_distance() const { return camera_distance; } + + private: + + /// Read all galaxy types + void read_galaxies(std::string const& path); + + /// Remove particles continuously + void remove_particles(); + + /// Execute a client request + jsoncons::json execute_json(std::string const& buffer); + + octree *tree; + + int server_socket; + + int client_socket; + + /// Number of users + static constexpr auto number_of_users = 4; + + /// Buffer size for socket data transmission + static constexpr auto buffer_size = 1024; + + /// Maximal number of particles of a user + static constexpr auto max_number_of_particles_of_user = 100000; + + /// Number of particles of user + my_dev::dev_mem user_particles; + + /// Dimension of the window + int window_width; + int window_height; + + /// OpenGL viewing angle + real fovy; + + /// OpenGL distance of clipping plane + real farZ; + + /// Distance of the OpenGL camera + real camera_distance; + + /// Dimension of the window + real simulation_plane_width; + real simulation_plane_height; + + /// Scaling factor for deletion sphere. + real deletion_radius_factor; + + /// Squared radius of deletion sphere. Particles leaving this sphere will be removed. + real deletion_radius_square; + + /// Galaxy types which can be released + std::vector galaxies; + +}; diff --git a/runtime/include/octree.h b/runtime/include/octree.h index a85b587..28c14f0 100644 --- a/runtime/include/octree.h +++ b/runtime/include/octree.h @@ -48,8 +48,7 @@ #include #endif - - +#include "Galaxy.h" typedef float real; typedef float2 real2; @@ -681,6 +680,14 @@ class octree { //End functions for parallel code + // WarOfGalaxies: add galaxy to simulation + void releaseGalaxy(Galaxy const& galaxy); + + // WarOfGalaxies: remove particles of a user + void removeGalaxy(int user_id); + + // WarOfGalaxies: remove particles out of sphere continuously + void removeParticles(real deletion_radius_square, my_dev::dev_mem &user_particles, int number_of_users); //Library interface functions void setEps(float eps); diff --git a/runtime/include/read_tipsy_file_parallel.h b/runtime/include/read_tipsy_file_parallel.h new file mode 100644 index 0000000..10e48a9 --- /dev/null +++ b/runtime/include/read_tipsy_file_parallel.h @@ -0,0 +1,21 @@ +/* + * read_tipsy_file_parallel.h + * + * Created on: May 6, 2016 + * Author: Bernd Doser + */ + +#pragma once + +#include +#include +#include + +void read_tipsy_file_parallel(std::vector &bodyPositions, std::vector &bodyVelocities, + std::vector &bodiesIDs, float eps2, string fileName, + int rank, int procs, int &NTotal2, int &NFirst, + int &NSecond, int &NThird, octree *tree, + std::vector &dustPositions, std::vector &dustVelocities, + std::vector &dustIDs, int reduce_bodies_factor, + int reduce_dust_factor, + const bool restart); diff --git a/runtime/include/renderloop.h b/runtime/include/renderloop.h index 8a340e4..baae4d1 100644 --- a/runtime/include/renderloop.h +++ b/runtime/include/renderloop.h @@ -2,12 +2,14 @@ #define _RENDERLOOP_H_ #include "octree.h" + extern float TstartGlow; extern float dTstartGlow; void initGL(int argc, char** argv, const char *fullScreenMode, bool &stereo); void initAppRenderer(int argc, char** argv, octree *tree, - octree::IterationData &idata, - bool showFPS, bool stereo); + octree::IterationData &idata, bool showFPS, bool stereo, + std::string const& wogPath, int wogPort, + real wogCameraDistance, real wogDeletionRadiusFactor); #endif // _RENDERLOOP_H_ diff --git a/runtime/include/thrust_war_of_galaxies.h b/runtime/include/thrust_war_of_galaxies.h new file mode 100644 index 0000000..9295756 --- /dev/null +++ b/runtime/include/thrust_war_of_galaxies.h @@ -0,0 +1,14 @@ +/* + * thrust_war_of_galaxies.h + * + * Created on: Jun 15, 2016 + * Author: Bernd Doser + */ + +#pragma once + +#include + +/// Remove particles behind visualization sphere +extern "C" void remove_particles(tree_structure &tree, + real deletion_radius_square, my_dev::dev_mem &user_particles, int number_of_users); diff --git a/runtime/src/Galaxy.cpp b/runtime/src/Galaxy.cpp new file mode 100644 index 0000000..41a8e92 --- /dev/null +++ b/runtime/src/Galaxy.cpp @@ -0,0 +1,88 @@ +/* + * Galaxy.cpp + * + * Created on: May 6, 2016 + * Author: Bernd Doser + */ + +#include + +real4 Galaxy::getCenterOfMass() const +{ + real mass; + real4 result = make_real4(0.0, 0.0, 0.0, 0.0); + for (auto const& p : pos) + { + mass = p.w; + result.x += mass * p.x; + result.y += mass * p.y; + result.z += mass * p.z; + result.w += mass; + } + + result.x /= result.w; + result.y /= result.w; + result.z /= result.w; + return result; +} + +real4 Galaxy::getCenterOfMassVelocity() const +{ + real mass; + real4 result = make_real4(0.0, 0.0, 0.0, 0.0); + for (size_t i = 0; i < vel.size(); i++) + { + mass = pos[i].w; + result.x += mass * vel[i].x; + result.y += mass * vel[i].y; + result.z += mass * vel[i].z; + result.w += mass; + } + + result.x /= result.w; + result.y /= result.w; + result.z /= result.w; + return result; +} + +void Galaxy::centering() +{ + real4 center_of_mass = getCenterOfMass(); + for (auto &p : pos) + { + p.x -= center_of_mass.x; + p.y -= center_of_mass.y; + p.z -= center_of_mass.z; + } +} + +void Galaxy::steady() +{ + real4 center_of_mass_velocity = getCenterOfMassVelocity(); + for (auto &v : vel) + { + v.x -= center_of_mass_velocity.x; + v.y -= center_of_mass_velocity.y; + v.z -= center_of_mass_velocity.z; + } +} + +void Galaxy::translate(real4 w) +{ + for (auto &p : pos) + { + p.x += w.x; + p.y += w.y; + p.z += w.z; + } +} + +void Galaxy::accelerate(real4 w) +{ + for (auto &v : vel) + { + v.x += w.x; + v.y += w.y; + v.z += w.z; + } +} diff --git a/runtime/src/WOGManager.cpp b/runtime/src/WOGManager.cpp new file mode 100644 index 0000000..0b5e8a3 --- /dev/null +++ b/runtime/src/WOGManager.cpp @@ -0,0 +1,314 @@ +/* + * WOGSocketManager.cpp + * + * Created on: May 17, 2016 + * Author: Bernd Doser + */ + +#include "read_tipsy_file_parallel.h" +#include "WOGManager.h" + +using jsoncons::json; + +#define DEBUG_PRINT + +WOGManager::WOGManager(octree *tree, std::string const& path, int port, int window_width, int window_height, real fovy, + real farZ, real camera_distance, real deletion_radius_factor) + : tree(tree), + server_socket(-1), + client_socket(-1), + user_particles(), + window_width(window_width), + window_height(window_height), + fovy(fovy), + farZ(farZ), + camera_distance(camera_distance), + simulation_plane_width(0.0), + simulation_plane_height(0.0), + deletion_radius_factor(deletion_radius_factor), + deletion_radius_square(0.0) +{ + user_particles.ccalloc(number_of_users); + + read_galaxies(path); + reshape(window_width, window_height); + + server_socket = socket(AF_INET, SOCK_STREAM, 0); + if (server_socket == -1) { + perror("socket"); + throw std::runtime_error("socket error"); + } + + int enable = 1; + if (setsockopt(server_socket, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int)) < 0) { + perror("setsockopt"); + throw std::runtime_error("setsockopt(SO_REUSEADDR) failed"); + } + + sockaddr_in serverAddr; + serverAddr.sin_family = AF_INET; + serverAddr.sin_port = htons(port); + serverAddr.sin_addr.s_addr = INADDR_ANY; + + std::cout << "Bind server socket to port " << std::to_string(port) << std::endl; + + if (bind(server_socket, (struct sockaddr*)&serverAddr, sizeof(struct sockaddr)) == -1) { + perror("bind"); + throw std::runtime_error("bind error"); + } + + // wait for a client + if (listen(server_socket, 5) == -1) { + perror("listen"); + throw std::runtime_error("listen error"); + } + + // Set server_socket to non-blocking + long save_fd = fcntl(server_socket, F_GETFL); + save_fd |= O_NONBLOCK; + fcntl(server_socket, F_SETFL, save_fd); +} + +WOGManager::~WOGManager() +{ + close(client_socket); + close(server_socket); +} + +void WOGManager::read_galaxies(std::string const& path) +{ + for (int i = 0;; ++i) + { + std::string filename = path + "/galaxy_type_" + std::to_string(i) + ".tipsy"; + if (access(filename.c_str(), F_OK) == -1) break; + std::cout << "Read file " << filename << " into GalaxyStore." << std::endl; + + Galaxy galaxy; + int Total2 = 0; + int NFirst = 0; + int NSecond = 0; + int NThird = 0; + + read_tipsy_file_parallel(galaxy.pos, galaxy.vel, galaxy.ids, + 0.0, filename.c_str(), 0, 1, Total2, NFirst, NSecond, NThird, nullptr, + galaxy.pos_dust, galaxy.vel_dust, galaxy.ids_dust, 1, 1, false); + + real4 cm = galaxy.getCenterOfMass(); + std::cout << "Center of mass = " << cm.x << " " << cm.y << " " << cm.z << std::endl; + real4 tv = galaxy.getCenterOfMassVelocity(); + std::cout << "Center_of_mass_velocity = " << tv.x << " " << tv.y << " " << tv.z << std::endl; + + galaxy.centering(); + galaxy.steady(); + + cm = galaxy.getCenterOfMass(); + std::cout << "Center of mass = " << cm.x << " " << cm.y << " " << cm.z << std::endl; + tv = galaxy.getCenterOfMassVelocity(); + std::cout << "Center_of_mass_velocity = " << tv.x << " " << tv.y << " " << tv.z << std::endl; + + galaxies.push_back(galaxy); + } +} + +void WOGManager::execute() +{ + // Remove particles + remove_particles(); + + // Check for a client + sockaddr_in clientAddr; + socklen_t sin_size = sizeof(struct sockaddr_in); + int new_client_socket = accept(server_socket, (struct sockaddr*)&clientAddr, &sin_size); + if (new_client_socket > 0) { + close(client_socket); + client_socket = new_client_socket; + } + + // Return if no client is connected + if (client_socket == -1) return; + + // Set client_socket to non-blocking + long save_fd = fcntl(client_socket, F_GETFL); + save_fd |= O_NONBLOCK; + fcntl(client_socket, F_SETFL, save_fd); + + // Check for user request + char buffer[buffer_size]; + int n = recv(client_socket, buffer, buffer_size, 0); + if (n <= 0) return; + buffer[n] = '\0'; + + json json_response; + + try { + json_response = execute_json(buffer); + } catch (std::exception const& e) { + std::cerr << "Error: " << e.what() << std::endl; + json_response["response"] = std::string("Error: ") + e.what(); + + } catch ( ... ) { + std::cerr << "Error: Unknown failure" << std::endl; + json_response["response"] = "Error: Unknown failure"; + } + + std::ostringstream oss; + oss << json_response; + std::string json_response_string = oss.str(); + + if (send(client_socket, json_response_string.c_str(), json_response_string.size(), 0) == -1) perror("send"); +} + +void WOGManager::reshape(int width, int height) +{ + window_width = width; + window_height = height; + real aspect_ratio = static_cast(window_width) / window_height; + + simulation_plane_height = 2 * camera_distance * tan(fovy * M_PI / 360.0); + simulation_plane_width = simulation_plane_height * aspect_ratio; + + std::cout << "window_width = " << window_width << std::endl; + std::cout << "window_height = " << window_height << std::endl; + std::cout << "aspect_ratio = " << aspect_ratio << std::endl; + std::cout << "simulation_plane_height = " << simulation_plane_height << std::endl; + std::cout << "simulation_plane_width = " << simulation_plane_width << std::endl; + + real4 rear_corner; + rear_corner.y = camera_distance * tan(fovy * M_PI / 360.0); + rear_corner.x = rear_corner.y * aspect_ratio; + rear_corner.z = farZ - camera_distance; + deletion_radius_square = rear_corner.x * rear_corner.x + rear_corner.y * rear_corner.y + rear_corner.z * rear_corner.z; + deletion_radius_square *= deletion_radius_factor * deletion_radius_factor; + #ifdef DEBUG_PRINT + std::cout << "deletion_radius_factor = " << deletion_radius_factor << std::endl; + std::cout << "deletion_radius = " << std::sqrt(deletion_radius_square) << std::endl; + #endif +} + +void WOGManager::remove_particles() +{ + tree->removeParticles(deletion_radius_square, user_particles, number_of_users); +} + +json WOGManager::execute_json(std::string const& json_request_string) +{ + json json_response; + + #ifdef DEBUG_PRINT + std::cout << "The JSON request is: " << json_request_string << std::endl; + #endif + + std::istringstream iss(json_request_string); + json json_request; + iss >> json_request; + + std::string task = json_request["task"].as(); + + #ifdef DEBUG_PRINT + std::cout << "task: " << task << std::endl; + #endif + + if (task == "release") + { + int user_id = json_request["user_id"].as(); + if (user_id < 0 or user_id >= number_of_users) throw std::runtime_error("Invalid user_id"); + + int galaxy_id = json_request["galaxy_id"].as(); + if (galaxy_id < 0 or galaxy_id >= galaxies.size()) throw std::runtime_error("Invalid galaxy_id"); + + std::vector vector_position = json_request["position"].as>(); + if (vector_position.size() > 3) throw std::runtime_error("Invalid dimension of position vector"); + + std::vector vector_velocity = json_request["velocity"].as>(); + if (vector_velocity.size() > 3) throw std::runtime_error("Invalid dimension of velocity vector"); + + real4 position = make_real4(0.0, 0.0, 0.0, 0.0); + + if (vector_position.size() > 0) { + if (vector_position[0] < 0.0 or vector_position[0] > 1.0) throw std::runtime_error("position.x out of range"); + position.x = vector_position[0] * simulation_plane_width; + } + if (vector_position.size() > 1) { + if (vector_position[1] < 0.0 or vector_position[1] > 1.0) throw std::runtime_error("position.y out of range"); + position.y = vector_position[1] * simulation_plane_height; + } + if (vector_position.size() > 2) { + if (vector_position[2] < -1.0 or vector_position[2] > 1.0) throw std::runtime_error("position.z out of range"); + if (vector_position[2] < 0.0) + position.z = vector_position[2] * camera_distance; + else + position.z = vector_position[2] * (farZ - camera_distance); + } + + // Shift center to lower left corner + position.x -= simulation_plane_width * 0.5; + position.y -= simulation_plane_height * 0.5; + + real4 velocity = make_real4(0.0, 0.0, 0.0, 0.0); + + if (vector_velocity.size() > 0) { + velocity.x = vector_velocity[0] * window_width / simulation_plane_width; + } + if (vector_velocity.size() > 1) { + velocity.y = vector_velocity[1] * window_height / simulation_plane_height; + } + if (vector_velocity.size() > 2) { + velocity.z = vector_velocity[2] * window_height / simulation_plane_height; + } + + #ifdef DEBUG_PRINT + std::cout << "user_id: " << user_id << std::endl; + std::cout << "galaxy_id: " << galaxy_id << std::endl; + std::cout << "position: " << position.x << " " << position.y << " " << position.z << std::endl; + std::cout << "velocity: " << velocity.x << " " << velocity.y << " " << velocity.z << std::endl; + #endif + + Galaxy galaxy = galaxies[galaxy_id]; + galaxy.translate(position); + galaxy.accelerate(velocity); + + // Since the particle ids are not needed for the simulation, we use them to store the user_id in the first digit. + for (auto & id : galaxy.ids) id = id - id % 10 + user_id; + + tree->releaseGalaxy(galaxy); + user_particles[user_id] += galaxy.pos.size(); + + std::cout << "Galaxy with " + std::to_string(galaxy.pos.size()) + " particles of user " + std::to_string(user_id) + " was released."; + json_response["response"] = task; + } + else if (task == "remove") + { + int user_id = json_request["user_id"].as(); + if (user_id < 0 or user_id >= number_of_users) throw std::runtime_error("Invalid user_id"); + + #ifdef DEBUG_PRINT + std::cout << "user_id: " << user_id << std::endl; + #endif + + tree->removeGalaxy(user_id); + user_particles[user_id] = 0; + + std::cout << "All particles of user " + std::to_string(user_id) + " were removed."; + json_response["response"] = task; + } + else if (task == "report") + { + std::cout << "Reporting current status."; + json_response["response"] = task; + } + else + { + throw std::runtime_error("Unknown task: " + task); + } + + // Always return the status information + // Simulation time in MYears, for factor see renderloop.cpp, search for MYears + json_response["simulation_time"] = tree->getTime() * 9.78; + json up = json::make_array<1>(number_of_users,0); + for (int ind = 0; ind < number_of_users; ind++) + up[ind] = user_particles[ind]; + json_response["user_particles"] = up; + std::cout << "user_particles: " << up; + + return json_response; +} diff --git a/runtime/src/gpu_iterate.cpp b/runtime/src/gpu_iterate.cpp index 7289a7c..db465d0 100644 --- a/runtime/src/gpu_iterate.cpp +++ b/runtime/src/gpu_iterate.cpp @@ -1,6 +1,10 @@ #undef NDEBUG #include "octree.h" -#include "postProcessModules.h" +#include "postProcessModules.h" + +#ifdef WAR_OF_GALAXIES +#include "thrust_war_of_galaxies.h" +#endif #include #include @@ -108,6 +112,197 @@ void octree::iterate_setup() { letRunning = false; } +void octree::releaseGalaxy(Galaxy const& galaxy) +{ + // Get particle data back to the host so we can add our new data + this->localTree.bodies_pos.d2h(); + this->localTree.bodies_acc0.d2h(); + this->localTree.bodies_vel.d2h(); + this->localTree.bodies_time.d2h(); + this->localTree.bodies_ids.d2h(); + this->localTree.bodies_Ppos.d2h(); + this->localTree.bodies_Pvel.d2h(); + + vector new_pos; + vector new_vel; + vector new_ids; + int old_nb_particles = this->localTree.n; + int new_nb_particles = old_nb_particles + galaxy.pos.size(); + + for (int i(0); i != old_nb_particles; ++i) + { + new_pos.push_back(this->localTree.bodies_pos[i]); + new_vel.push_back(this->localTree.bodies_vel[i]); + new_ids.push_back(this->localTree.bodies_ids[i]); + } + + for (int i(0); i != galaxy.pos.size(); ++i) + { + new_pos.push_back(galaxy.pos[i]); + new_vel.push_back(galaxy.vel[i]); + new_ids.push_back(galaxy.ids[i]); + } + + // Set new size of the buffers + this->localTree.setN(new_nb_particles); + + // Resize preserves original data + this->reallocateParticleMemory(this->localTree); + + // Copy back to host storage + memcpy(&this->localTree.bodies_pos[0], &new_pos[0], sizeof(real4) * new_nb_particles); + memcpy(&this->localTree.bodies_vel[0], &new_vel[0], sizeof(real4) * new_nb_particles); + memcpy(&this->localTree.bodies_ids[0], &new_ids[0], sizeof(ullong) * new_nb_particles); + + float2 curTime = this->localTree.bodies_time[0]; + for (int i(0); i != new_nb_particles; ++i) + this->localTree.bodies_time[i] = curTime; + for (int i(old_nb_particles); i != new_nb_particles; ++i) + this->localTree.bodies_acc0[i] = make_float4(0.0, 0.0, 0.0, 0.0); + this->localTree.bodies_acc1.zeroMem(); + + this->localTree.bodies_pos.h2d(); + this->localTree.bodies_acc0.h2d(); + this->localTree.bodies_vel.h2d(); + this->localTree.bodies_time.h2d(); + this->localTree.bodies_ids.h2d(); + + // Fill the predicted arrays + this->localTree.bodies_Ppos.copy(this->localTree.bodies_pos, localTree.n); + this->localTree.bodies_Pvel.copy(this->localTree.bodies_pos, localTree.n); + + resetEnergy(); +} + +void octree::removeGalaxy(int user_id) +{ + // Get particle data back to the host so we can add our new data + this->localTree.bodies_pos.d2h(); + this->localTree.bodies_vel.d2h(); + this->localTree.bodies_ids.d2h(); + this->localTree.bodies_acc0.d2h(); + this->localTree.bodies_time.d2h(); + this->localTree.bodies_Ppos.d2h(); + this->localTree.bodies_Pvel.d2h(); + + vector new_pos; + vector new_vel; + vector new_ids; + int old_nb_particles = this->localTree.n; + int new_nb_particles = 0; + + for (int i(0); i != old_nb_particles; ++i) + { + if (this->localTree.bodies_ids[i] % 10 == user_id) continue; + new_pos.push_back(this->localTree.bodies_pos[i]); + new_vel.push_back(this->localTree.bodies_vel[i]); + new_ids.push_back(this->localTree.bodies_ids[i]); + ++new_nb_particles; + } + + // Set new size of the buffers + this->localTree.setN(new_nb_particles); + + // Resize preserves original data + this->reallocateParticleMemory(this->localTree); + + // Copy back to host storage + memcpy(&this->localTree.bodies_pos[0], &new_pos[0], sizeof(real4) * new_nb_particles); + memcpy(&this->localTree.bodies_vel[0], &new_vel[0], sizeof(real4) * new_nb_particles); + memcpy(&this->localTree.bodies_ids[0], &new_ids[0], sizeof(ullong) * new_nb_particles); + + float2 curTime = this->localTree.bodies_time[0]; + for(int i=0; i < this->localTree.n; i++) + this->localTree.bodies_time[i] = curTime; + this->localTree.bodies_acc1.zeroMem(); + + this->localTree.bodies_pos.h2d(); + this->localTree.bodies_acc0.h2d(); + this->localTree.bodies_vel.h2d(); + this->localTree.bodies_time.h2d(); + this->localTree.bodies_ids.h2d(); + + // Fill the predicted arrays + this->localTree.bodies_Ppos.copy(this->localTree.bodies_pos, localTree.n); + this->localTree.bodies_Pvel.copy(this->localTree.bodies_pos, localTree.n); + + resetEnergy(); +} + +void octree::removeParticles(real deletion_radius_square, my_dev::dev_mem &user_particles, int number_of_users) +{ +#if defined WAR_OF_GALAXIES && defined USE_THRUST + + user_particles.h2d(); + remove_particles(this->localTree, deletion_radius_square, user_particles, number_of_users); + user_particles.d2h(); + + // Resize preserves original data + this->reallocateParticleMemory(this->localTree); + +#else + + // Get particle data back to the host so we can add our new data + this->localTree.bodies_pos.d2h(); + this->localTree.bodies_vel.d2h(); + this->localTree.bodies_ids.d2h(); + this->localTree.bodies_acc0.d2h(); + this->localTree.bodies_time.d2h(); + this->localTree.bodies_Ppos.d2h(); + this->localTree.bodies_Pvel.d2h(); + + vector new_pos; + vector new_vel; + vector new_ids; + int old_nb_particles = this->localTree.n; + int new_nb_particles = 0; + + for (int i(0); i != old_nb_particles; ++i) + { + real4 position = this->localTree.bodies_pos[i]; + if (position.x * position.x + position.y * position.y + position.z * position.z > deletion_radius_square + and this->localTree.bodies_ids[i] % 10 != 9) + { + --user_particles[this->localTree.bodies_ids[i] % 10]; + continue; + } + new_pos.push_back(this->localTree.bodies_pos[i]); + new_vel.push_back(this->localTree.bodies_vel[i]); + new_ids.push_back(this->localTree.bodies_ids[i]); + ++new_nb_particles; + } + + // Set new size of the buffers + this->localTree.setN(new_nb_particles); + + // Resize preserves original data + this->reallocateParticleMemory(this->localTree); + + // Copy back to host storage + memcpy(&this->localTree.bodies_pos[0], &new_pos[0], sizeof(real4) * new_nb_particles); + memcpy(&this->localTree.bodies_vel[0], &new_vel[0], sizeof(real4) * new_nb_particles); + memcpy(&this->localTree.bodies_ids[0], &new_ids[0], sizeof(ullong) * new_nb_particles); + + float2 curTime = this->localTree.bodies_time[0]; + for(int i=0; i < this->localTree.n; i++) + this->localTree.bodies_time[i] = curTime; + this->localTree.bodies_acc1.zeroMem(); + + this->localTree.bodies_pos.h2d(); + this->localTree.bodies_acc0.h2d(); + this->localTree.bodies_vel.h2d(); + this->localTree.bodies_time.h2d(); + this->localTree.bodies_ids.h2d(); + + // Fill the predicted arrays + this->localTree.bodies_Ppos.copy(this->localTree.bodies_pos, localTree.n); + this->localTree.bodies_Pvel.copy(this->localTree.bodies_pos, localTree.n); + +#endif + + resetEnergy(); +} + // returns true if this iteration is the last (t_current >= t_end), false otherwise bool octree::iterate_once(IterationData &idata) { double t1 = 0; @@ -389,7 +584,7 @@ bool octree::iterate_once(IterationData &idata) { } } - +#ifndef WAR_OF_GALAXIES if (iter >= iterEnd) return true; if(t_current >= tEnd) @@ -401,6 +596,7 @@ bool octree::iterate_once(IterationData &idata) { return true; } iter++; +#endif return false; } @@ -963,7 +1159,7 @@ double octree::compute_energies(tree_structure &tree) if(mpiGetRank() == 0) { -#if 0 +#ifdef WAR_OF_GALAXIES LOG("iter=%d : time= %lg Etot= %.10lg Ekin= %lg Epot= %lg : de= %lg ( %lg ) d(de)= %lg ( %lg ) t_sim= %lg sec\n", iter, this->t_current, Etot, Ekin, Epot, de, de_max, dde, dde_max, get_time() - tinit); LOGF(stderr, "iter=%d : time= %lg Etot= %.10lg Ekin= %lg Epot= %lg : de= %lg ( %lg ) d(de)= %lg ( %lg ) t_sim= %lg sec\n", diff --git a/runtime/src/main.cpp b/runtime/src/main.cpp index 1504e3a..df153a3 100644 --- a/runtime/src/main.cpp +++ b/runtime/src/main.cpp @@ -63,6 +63,8 @@ Leiden Observatory, Leiden University #include "anyoption.h" #include "renderloop.h" +#include "read_tipsy_file_parallel.h" + #include #include @@ -117,7 +119,22 @@ extern void displayTimers() #include #endif +#ifdef WAR_OF_GALAXIES +#include +void throw_if_flag_is_used(AnyOption const& opt, std::vector arguments) +{ + for (auto const& arg : arguments) + // Error in AnyOption: getter function not const + if (const_cast(opt).getFlag(arg.c_str())) throw std::runtime_error(arg + " is not valid in war-of-galaxy mode."); +} +void throw_if_option_is_used(AnyOption const& opt, std::vector arguments) +{ + for (auto const& arg : arguments) + // Error in AnyOption: getter function not const + if (const_cast(opt).getValue(arg.c_str()) != nullptr) throw std::runtime_error(arg + " is not valid in war-of-galaxy mode."); +} +#endif @@ -229,6 +246,12 @@ int main(int argc, char** argv, MPI_Comm comm, int shrMemPID) int nCube = -1; int nMilkyWay = -1; int nMWfork = 4; + + std::string wogPath; + int wogPort = 50007; + real wogCameraDistance = 500.0; + real wogDeletionRadiusFactor = 1.0; + int galSeed = 0; std::string taskVar; //#define TITAN_G @@ -296,6 +319,12 @@ int main(int argc, char** argv, MPI_Comm comm, int shrMemPID) ADDUSAGE(" --cube # use cube model with # particles per proc"); ADDUSAGE(" --diskmode use diskmode to read same input file all MPI taks and randomly shuffle its positions"); ADDUSAGE(" --mpirendermode use MPI to communicate with the renderer. Must only be used with bonsai_driver. [disabled]"); +#ifdef WAR_OF_GALAXIES + ADDUSAGE(" --war-of-galaxies # input path for WarOfGalaxies"); + ADDUSAGE(" --port # Port for WarOfGalaxies"); + ADDUSAGE(" --camera-distance # OpenGL camera distance for WarOfGalaxies"); + ADDUSAGE(" --del-radius-factor # Scaling factor of deletion sphere for WarOfGalaxies"); +#endif ADDUSAGE(" "); @@ -345,6 +374,10 @@ int main(int argc, char** argv, MPI_Comm comm, int shrMemPID) opt.setFlag("displayfps"); opt.setFlag("stereo"); #endif + opt.setOption("war-of-galaxies"); + opt.setOption("port"); + opt.setOption("camera-distance"); + opt.setOption("del-radius-factor"); opt.processCommandArgs( argc, argv ); @@ -396,6 +429,10 @@ int main(int argc, char** argv, MPI_Comm comm, int shrMemPID) if ((optarg = opt.getValue("rebuild"))) rebuild_tree_rate = atoi (optarg); if ((optarg = opt.getValue("reducebodies"))) reduce_bodies_factor = atoi (optarg); if ((optarg = opt.getValue("reducedust"))) reduce_dust_factor = atoi (optarg); + if ((optarg = opt.getValue("war-of-galaxies"))) wogPath = string(optarg); + if ((optarg = opt.getValue("port"))) wogPort = atoi(optarg); + if ((optarg = opt.getValue("camera-distance"))) wogCameraDistance = atof(optarg); + if ((optarg = opt.getValue("del-radius-factor"))) wogDeletionRadiusFactor = atof(optarg); #if USE_OPENGL if ((optarg = opt.getValue("fullscreen"))) fullScreenMode = string(optarg); if ((optarg = opt.getValue("Tglow"))) TstartGlow = (float)atof(optarg); @@ -413,6 +450,13 @@ int main(int argc, char** argv, MPI_Comm comm, int shrMemPID) ::exit(0); } +#ifdef WAR_OF_GALAXIES + /// WarOfGalaxies: Deactivate unneeded flags using WarOfGalaxies + throw_if_flag_is_used(opt, {{"direct", "restart", "diskmode", "stereo", "prepend-rank"}}); + throw_if_option_is_used(opt, {{"plummer", "milkyway", "mwfork", "sphere", "tend", "iend", + "snapname", "snapiter", "rmdist", "valueadd", "rebuild", "reducedust", "gameMode"}}); +#endif + #undef ADDUSAGE } #endif @@ -705,6 +749,59 @@ int main(int argc, char** argv, MPI_Comm comm, int shrMemPID) } else if ((nPlummer == -1 && nSphere == -1 && nCube == -1 && !diskmode && nMilkyWay == -1) || restartSim) { +#ifdef WAR_OF_GALAXIES + std::cout << "WarOfGalaxies: Input file is used as dummy particles." << std::endl; + for (auto & id : bodyIDs) id = id - id % 10 + 9; + + // get center of mass + real mass; + real4 center_of_mass = make_real4(0.0, 0.0, 0.0, 0.0); + + for (auto const& p : bodyPositions) + { + mass = p.w; + center_of_mass.x += mass * p.x; + center_of_mass.y += mass * p.y; + center_of_mass.z += mass * p.z; + center_of_mass.w += mass; + } + + center_of_mass.x /= center_of_mass.w; + center_of_mass.y /= center_of_mass.w; + center_of_mass.z /= center_of_mass.w; + + // get center-of-mass velocity + real4 center_of_mass_velocity = make_real4(0.0, 0.0, 0.0, 0.0); + + for (size_t i = 0; i < bodyVelocities.size(); i++) + { + mass = bodyPositions[i].w; + center_of_mass_velocity.x += mass * bodyVelocities[i].x; + center_of_mass_velocity.y += mass * bodyVelocities[i].y; + center_of_mass_velocity.z += mass * bodyVelocities[i].z; + center_of_mass_velocity.w += mass; + } + + center_of_mass_velocity.x /= center_of_mass_velocity.w; + center_of_mass_velocity.y /= center_of_mass_velocity.w; + center_of_mass_velocity.z /= center_of_mass_velocity.w; + + // shift center of mass to position (0,0,10000) + for (auto &p : bodyPositions) + { + p.x -= center_of_mass.x; + p.y -= center_of_mass.y; + p.z -= center_of_mass.z + 10000; + } + + // steady + for (auto &v : bodyVelocities) + { + v.x -= center_of_mass_velocity.x; + v.y -= center_of_mass_velocity.y; + v.z -= center_of_mass_velocity.z; + } +#endif float sTime = 0; tree->fileIO->readFile(mpiCommWorld, bodyPositions, bodyVelocities, bodyIDs, fileName, procId, nProcs, sTime, reduce_bodies_factor, restartSim); @@ -804,7 +901,8 @@ int main(int argc, char** argv, MPI_Comm comm, int shrMemPID) //Start the integration #ifdef USE_OPENGL octree::IterationData idata; - initAppRenderer(argc, argv, tree, idata, displayFPS, stereo); + initAppRenderer(argc, argv, tree, idata, displayFPS, stereo, + wogPath, wogPort, wogCameraDistance, wogDeletionRadiusFactor); LOG("Finished!!! Took in total: %lg sec\n", tree->get_time()-t0); #else tree->mpiSync(); diff --git a/runtime/src/read_tipsy_file_parallel.cpp b/runtime/src/read_tipsy_file_parallel.cpp new file mode 100644 index 0000000..1c68bbc --- /dev/null +++ b/runtime/src/read_tipsy_file_parallel.cpp @@ -0,0 +1,186 @@ +/* + * read_tipsy_file_parallel.cpp + * + * Created on: May 6, 2016 + * Author: Bernd Doser + */ + +#include "read_tipsy_file_parallel.h" + +using namespace std; + +void read_tipsy_file_parallel(std::vector &bodyPositions, std::vector &bodyVelocities, + std::vector &bodiesIDs, float eps2, string fileName, + int rank, int procs, int &NTotal2, int &NFirst, + int &NSecond, int &NThird, octree *tree, + std::vector &dustPositions, std::vector &dustVelocities, + std::vector &dustIDs, int reduce_bodies_factor, + int reduce_dust_factor, + const bool restart) +{ + //Process 0 does the file reading and sends the data + //to the other processes + /* + + Read in our custom version of the tipsy file format. + Most important change is that we store particle id on the + location where previously the potential was stored. + */ + + + char fullFileName[256]; + if(restart) + sprintf(fullFileName, "%s%d", fileName.c_str(), rank); + else + sprintf(fullFileName, "%s", fileName.c_str()); + + LOG("Trying to read file: %s \n", fullFileName); + + + + ifstream inputFile(fullFileName, ios::in | ios::binary); + if(!inputFile.is_open()) + { + LOG("Can't open input file \n"); + exit(0); + } + + dump h; + inputFile.read((char*)&h, sizeof(h)); + + int NTotal; + int idummy; + real4 positions; + real4 velocity; + + + //Read tipsy header + NTotal = h.nbodies; + NFirst = h.ndark; + NSecond = h.nstar; + NThird = h.nsph; + + if (tree) tree->set_t_current((float) h.time); + + //Rough divide + uint perProc = (NTotal / procs) /reduce_bodies_factor; + if(restart) perProc = NTotal /reduce_bodies_factor; //don't subdivide when using restart + bodyPositions.reserve(perProc+10); + bodyVelocities.reserve(perProc+10); + bodiesIDs.reserve(perProc+10); + perProc -= 1; + + //Start reading + int particleCount = 0; + int procCntr = 1; + + dark_particle d; + star_particle s; + + int globalParticleCount = 0; + int bodyCount = 0; + int dustCount = 0; + + for(int i=0; i < NTotal; i++) + { + if(i < NFirst) + { + inputFile.read((char*)&d, sizeof(d)); + velocity.w = d.eps; + positions.w = d.mass; + positions.x = d.pos[0]; + positions.y = d.pos[1]; + positions.z = d.pos[2]; + velocity.x = d.vel[0]; + velocity.y = d.vel[1]; + velocity.z = d.vel[2]; + idummy = d.phi; + } + else + { + inputFile.read((char*)&s, sizeof(s)); + velocity.w = s.eps; + positions.w = s.mass; + positions.x = s.pos[0]; + positions.y = s.pos[1]; + positions.z = s.pos[2]; + velocity.x = s.vel[0]; + velocity.y = s.vel[1]; + velocity.z = s.vel[2]; + idummy = s.phi; + } + + + if(positions.z < -10e10) + { + fprintf(stderr," Removing particle %d because of Z is: %f \n", globalParticleCount, positions.z); + continue; + } + + + globalParticleCount++; + + #ifdef USE_DUST + if(idummy >= 50000000 && idummy < 100000000) + { + dustCount++; + if( dustCount % reduce_dust_factor == 0 ) + positions.w *= reduce_dust_factor; + + if( dustCount % reduce_dust_factor != 0 ) + continue; + dustPositions.push_back(positions); + dustVelocities.push_back(velocity); + dustIDs.push_back(idummy); + } + else + { + bodyCount++; + if( bodyCount % reduce_bodies_factor == 0 ) + positions.w *= reduce_bodies_factor; + + if( bodyCount % reduce_bodies_factor != 0 ) + continue; + bodyPositions.push_back(positions); + bodyVelocities.push_back(velocity); + bodiesIDs.push_back(idummy); + } + + + #else + if( globalParticleCount % reduce_bodies_factor == 0 ) + positions.w *= reduce_bodies_factor; + + if( globalParticleCount % reduce_bodies_factor != 0 ) + continue; + bodyPositions.push_back(positions); + bodyVelocities.push_back(velocity); + bodiesIDs.push_back(idummy); + #endif + + particleCount++; + + +// if(!restart) +// { +// if(bodyPositions.size() > perProc && procCntr != procs) +// { +// if (tree) tree->ICSend(procCntr, &bodyPositions[0], &bodyVelocities[0], &bodiesIDs[0], (int)bodyPositions.size()); +// procCntr++; +// +// bodyPositions.clear(); +// bodyVelocities.clear(); +// bodiesIDs.clear(); +// } +// } + }//end while + + inputFile.close(); + + //Clear the last one since its double +// bodyPositions.resize(bodyPositions.size()-1); +// NTotal2 = particleCount-1; + NTotal2 = particleCount; + LOGF(stderr,"NTotal: %d\tper proc: %d\tFor ourself: %d \tNDust: %d \n", + NTotal, perProc, (int)bodiesIDs.size(), (int)dustPositions.size()); +} diff --git a/runtime/src/renderloop.cpp b/runtime/src/renderloop.cpp index b5c3e25..5d116c2 100644 --- a/runtime/src/renderloop.cpp +++ b/runtime/src/renderloop.cpp @@ -33,6 +33,10 @@ #include "tr.h" +#ifdef WAR_OF_GALAXIES +#include "WOGManager.h" +#endif + float TstartGlow; float dTstartGlow; @@ -312,16 +316,17 @@ void glPrintf(float x, float y, const char* format, ...) class BonsaiDemo { public: - BonsaiDemo(octree *tree, octree::IterationData &idata) + BonsaiDemo(octree *tree, octree::IterationData &idata, + std::string const& wogPath, int wogPort, real wogCameraDistance, real wogDeletionRadiusFactor) : m_tree(tree), m_idata(idata), iterationsRemaining(true), -// m_renderer(tree->localTree.n + tree->localTree.n_dust), +// m_renderer(tree->localTree.n + tree->localTree.n_dust), m_renderer(tree->localTree.n, MAX_PARTICLES), - //m_displayMode(ParticleRenderer::PARTICLE_SPRITES_COLOR), - m_displayMode(SmokeRenderer::VOLUMETRIC), +// m_displayMode(ParticleRenderer::PARTICLE_SPRITES_COLOR), + m_displayMode(SmokeRenderer::VOLUMETRIC), m_ox(0), m_oy(0), m_buttonState(0), m_inertia(0.2f), m_paused(false), m_renderingEnabled(true), - m_displayBoxes(false), + m_displayBoxes(false), m_displaySliders(false), m_displayCursor(1), m_cursorSize(0.5), @@ -331,12 +336,16 @@ class BonsaiDemo m_octreeMinDepth(0), m_octreeMaxDepth(3), m_flyMode(false), - m_fov(60.0f), - m_nearZ(0.2), - m_screenZ(450.0), - m_farZ(2000), - m_IOD(4.0), - m_stereoEnabled(false), //SV TODO Must be false, never make it true + m_fov(60.0f), + m_nearZ(0.2), + m_screenZ(450.0), +#ifdef WAR_OF_GALAXIES + m_farZ(1000), +#else + m_farZ(2000), +#endif + m_IOD(4.0), + m_stereoEnabled(false), //SV TODO Must be false, never make it true m_supernova(false), m_overBright(1.0f), m_params(m_renderer.getParams()), @@ -344,7 +353,12 @@ class BonsaiDemo m_displayBodiesSec(true), m_cameraRollHome(0.0f), m_cameraRoll(0.0f), +#ifdef WAR_OF_GALAXIES + m_enableStats(false), + m_wogManager(tree, wogPath, wogPort, 1024, 768, m_fov, m_farZ, wogCameraDistance, wogDeletionRadiusFactor), +#else m_enableStats(true), +#endif m_densityRange(100) { m_windowDims = make_int2(WINDOWW, WINDOWH); @@ -677,7 +691,9 @@ class BonsaiDemo glRotatef(m_cameraRotLag.x, 1.0, 0.0, 0.0); glRotatef(m_cameraRotLag.y, 0.0, 1.0, 0.0); glRotatef(m_cameraRoll, 0.0, 0.0, 1.0); +#ifndef WAR_OF_GALAXIES glRotatef(90.0f, 1.0f, 0.0f, 0.0f); // rotate galaxies into XZ plane +#endif } glGetFloatv(GL_MODELVIEW_MATRIX, m_modelView); @@ -1011,6 +1027,7 @@ class BonsaiDemo m_cameraRoll -= 2.0f; break; case 'W': + break; default: break; } @@ -1089,6 +1106,9 @@ class BonsaiDemo m_renderer.setFOV(m_fov); m_renderer.setWindowSize(m_windowDims.x, m_windowDims.y); +#ifdef WAR_OF_GALAXIES + m_wogManager.reshape(w, h); +#endif fitCamera(); glMatrixMode(GL_MODELVIEW); @@ -1106,7 +1126,11 @@ class BonsaiDemo float distanceToCenter = radius / sinf(0.5f * fovRads); +#ifdef WAR_OF_GALAXIES + m_cameraTrans = make_float3(0, 0, -m_wogManager.get_camera_distance()); +#else m_cameraTrans = center + make_float3(0, 0, -distanceToCenter*0.2f); +#endif #if 0 /* JB This came with stereo, seems to break rotation */ @@ -1496,6 +1520,11 @@ class BonsaiDemo ParamListGL *m_colorParams; ParamListGL *m_params; // current +#ifdef WAR_OF_GALAXIES + /// Managing class for WarOfGalaxies + WOGManager m_wogManager; +#endif + // saved cameras struct Camera { Camera() { @@ -1817,13 +1846,16 @@ void keyUp(unsigned char key, int /*x*/, int /*y*/) void special(int key, int x, int y) { - theDemo->special(key); - glutPostRedisplay(); + theDemo->special(key); + glutPostRedisplay(); } void idle(void) { - glutPostRedisplay(); +#ifdef WAR_OF_GALAXIES + theDemo->m_wogManager.execute(); +#endif + glutPostRedisplay(); } void initGL(int argc, char** argv, const char *fullScreenMode, bool &stereo) @@ -1913,12 +1945,13 @@ void initGL(int argc, char** argv, const char *fullScreenMode, bool &stereo) atexit(onexit); } - -void initAppRenderer(int argc, char** argv, octree *tree, - octree::IterationData &idata, bool showFPS, bool stereo) { +void initAppRenderer(int argc, char** argv, octree *tree, octree::IterationData &idata, + bool showFPS, bool stereo, std::string const& wogPath, int wogPort, + real wogCameraDistance, real wogDeletionRadiusFactor) +{ displayFps = showFPS; //initGL(argc, argv); - theDemo = new BonsaiDemo(tree, idata); + theDemo = new BonsaiDemo(tree, idata, wogPath, wogPort, wogCameraDistance, wogDeletionRadiusFactor); if (stereo) theDemo->toggleStereo(); //SV assuming stereo is set to disable by default. glutMainLoop(); diff --git a/tools/war-of-galaxies/Jenkinsfile b/tools/war-of-galaxies/Jenkinsfile new file mode 100644 index 0000000..b9744aa --- /dev/null +++ b/tools/war-of-galaxies/Jenkinsfile @@ -0,0 +1,47 @@ +#!groovy + +pipeline { + agent { + docker { + image 'bernddoser/docker-devel-cpp:cuda-9.1-devel-cmake-3.10' + } + } + stages { + stage('Build') { + steps { + sh ''' + git submodule init + git submodule update + mkdir -p build + cd build + cmake -DCMAKE_BUILD_TYPE=release \ + -DUSE_OPENGL=ON \ + -DUSE_MPI=OFF \ + -DUSE_CUB=OFF \ + -DUSE_THRUST=ON \ + -DWAR_OF_GALAXIES=ON \ + ../runtime/ + make 2>&1 |tee make.out + ''' + } + post { + always { + step([ + $class: 'WarningsPublisher', canComputeNew: false, canResolveRelativePaths: false, + defaultEncoding: '', excludePattern: '', healthy: '', includePattern: '', messagesPattern: '', + parserConfigurations: [[parserName: 'GNU Make + GNU C Compiler (gcc)', pattern: 'build/make.out']], + unHealthy: '' + ]) + } + } + } + } + post { + success { + mail to: 'bernd.doser@h-its.org', subject: "SUCCESS: ${currentBuild.fullDisplayName}", body: "All fine." + } + failure { + mail to: 'bernd.doser@h-its.org', subject: "FAILURE: ${currentBuild.fullDisplayName}", body: "Failed." + } + } +} diff --git a/tools/war-of-galaxies/README.md b/tools/war-of-galaxies/README.md new file mode 100644 index 0000000..b065cf9 --- /dev/null +++ b/tools/war-of-galaxies/README.md @@ -0,0 +1,58 @@ +War of galaxies +=============== + +Installation +------------ + +Before the compilation the git submodule must be updated with + +``` +git submodule init +git submodule update +``` + +Compile with + +``` +cmake \ + -DCMAKE_BUILD_TYPE=release \ + -DUSE_OPENGL=ON \ + -DUSE_MPI=OFF \ + -DUSE_CUB=OFF \ + -DUSE_THRUST=ON \ + -DWAR_OF_GALAXIES=ON \ + /runtime/ +make -j +``` + +Usage +----- + +Starting Bonsai with + +``` +./bonsai2_slowdust \ + -i /tools/war-of-galaxies/galaxy_types/dummy.tipsy \ + --war-of-galaxies /tools/war-of-galaxies/galaxy_types/available +``` + +will show an empty simulation. In trues there is a single dummy particle at +position (0,0,10000) with zero mass, because Bonsai can not run without any +particles. + +Actual galaxies are located or symlinked in +`/tools/war-of-galaxies/galaxy_types/available`, with the naming +scheme identifying the galaxy numbering. + +The release (insertion) or removal of galaxies will be controlled by json +commands. Therefore, you can start the python script: + +``` +/tools/war-of-galaxies/client_json.py +``` + +Please find examples of json commands at + +``` +/tools/war-of-galaxies/json_examples.txt +``` diff --git a/tools/war-of-galaxies/client_json.py b/tools/war-of-galaxies/client_json.py new file mode 100755 index 0000000..031447e --- /dev/null +++ b/tools/war-of-galaxies/client_json.py @@ -0,0 +1,26 @@ +#!/usr/bin/python + +import json +import socket +import sys + +HOST = 'localhost' +PORT = 50007 +BUFFERSIZE = 1024 + +s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) +s.connect((HOST, PORT)) + +while 1: + + send_json = raw_input("JSON string: ") + if send_json == "exit": + break + s.send(send_json) + + recv_json = s.recv(BUFFERSIZE) + print "Received data:", recv_json + +s.shutdown(socket.SHUT_RDWR) +s.close() + diff --git a/tools/war-of-galaxies/galaxy_types/available/galaxy_type_0.tipsy b/tools/war-of-galaxies/galaxy_types/available/galaxy_type_0.tipsy new file mode 120000 index 0000000..0736d42 --- /dev/null +++ b/tools/war-of-galaxies/galaxy_types/available/galaxy_type_0.tipsy @@ -0,0 +1 @@ +../testSolar_5M_galaxy1_reduce50.tipsy \ No newline at end of file diff --git a/tools/war-of-galaxies/galaxy_types/available/galaxy_type_1.tipsy b/tools/war-of-galaxies/galaxy_types/available/galaxy_type_1.tipsy new file mode 120000 index 0000000..28eb85f --- /dev/null +++ b/tools/war-of-galaxies/galaxy_types/available/galaxy_type_1.tipsy @@ -0,0 +1 @@ +../testSolar_5M_galaxy2_reduce50.tipsy \ No newline at end of file diff --git a/tools/war-of-galaxies/galaxy_types/available/galaxy_type_2.tipsy b/tools/war-of-galaxies/galaxy_types/available/galaxy_type_2.tipsy new file mode 120000 index 0000000..2720be5 --- /dev/null +++ b/tools/war-of-galaxies/galaxy_types/available/galaxy_type_2.tipsy @@ -0,0 +1 @@ +../model3_child_compact_reduce50.tipsy \ No newline at end of file diff --git a/tools/war-of-galaxies/galaxy_types/available/galaxy_type_3.tipsy b/tools/war-of-galaxies/galaxy_types/available/galaxy_type_3.tipsy new file mode 120000 index 0000000..a8adbf9 --- /dev/null +++ b/tools/war-of-galaxies/galaxy_types/available/galaxy_type_3.tipsy @@ -0,0 +1 @@ +../model3_child_compact.tipsy \ No newline at end of file diff --git a/tools/war-of-galaxies/galaxy_types/dummy.tipsy b/tools/war-of-galaxies/galaxy_types/dummy.tipsy new file mode 100644 index 0000000..26fee6c Binary files /dev/null and b/tools/war-of-galaxies/galaxy_types/dummy.tipsy differ diff --git a/tools/war-of-galaxies/galaxy_types/model3_child_compact.tipsy b/tools/war-of-galaxies/galaxy_types/model3_child_compact.tipsy new file mode 100644 index 0000000..fce956c Binary files /dev/null and b/tools/war-of-galaxies/galaxy_types/model3_child_compact.tipsy differ diff --git a/tools/war-of-galaxies/galaxy_types/model3_child_compact_reduce50.tipsy b/tools/war-of-galaxies/galaxy_types/model3_child_compact_reduce50.tipsy new file mode 100644 index 0000000..9799928 Binary files /dev/null and b/tools/war-of-galaxies/galaxy_types/model3_child_compact_reduce50.tipsy differ diff --git a/tools/war-of-galaxies/galaxy_types/testSolar_5M_galaxy1_reduce50.tipsy b/tools/war-of-galaxies/galaxy_types/testSolar_5M_galaxy1_reduce50.tipsy new file mode 100644 index 0000000..81d5c89 Binary files /dev/null and b/tools/war-of-galaxies/galaxy_types/testSolar_5M_galaxy1_reduce50.tipsy differ diff --git a/tools/war-of-galaxies/galaxy_types/testSolar_5M_galaxy2_reduce50.tipsy b/tools/war-of-galaxies/galaxy_types/testSolar_5M_galaxy2_reduce50.tipsy new file mode 100644 index 0000000..d9bb9c3 Binary files /dev/null and b/tools/war-of-galaxies/galaxy_types/testSolar_5M_galaxy2_reduce50.tipsy differ diff --git a/tools/war-of-galaxies/json_examples.txt b/tools/war-of-galaxies/json_examples.txt new file mode 100644 index 0000000..e8f845a --- /dev/null +++ b/tools/war-of-galaxies/json_examples.txt @@ -0,0 +1,26 @@ +{ "task": "release", "galaxy_id": 1, "user_id": 0, "position": [], "velocity": [] } +{ "task": "release", "galaxy_id": 1, "user_id": 1, "position": [1], "velocity": [] } +{ "task": "release", "galaxy_id": 1, "user_id": 2, "position": [0,1], "velocity": [] } +{ "task": "release", "galaxy_id": 1, "user_id": 3, "position": [1,1], "velocity": [] } +{ "task": "report" } +{ "task": "remove", "user_id": 0 } +{ "task": "remove", "user_id": 1 } +{ "task": "remove", "user_id": 2 } +{ "task": "remove", "user_id": 3 } +{ "task": "report" } +{ "task": "release", "galaxy_id": 0, "user_id": 0, "position": [0.1, 0.1], "velocity": [ 5, 5] } +{ "task": "release", "galaxy_id": 1, "user_id": 1, "position": [0.9, 0.1], "velocity": [-5, 5] } +{ "task": "release", "galaxy_id": 0, "user_id": 2, "position": [0.1, 0.9], "velocity": [ 5, -5] } +{ "task": "release", "galaxy_id": 1, "user_id": 3, "position": [0.9, 0.9], "velocity": [-5, -5] } +{ "task": "report" } +{ "task": "remove", "user_id": 0 } +{ "task": "remove", "user_id": 1 } +{ "task": "remove", "user_id": 2 } +{ "task": "remove", "user_id": 3 } +{ "task": "report" } +{ "task": "release", "galaxy_id": 0, "user_id": 0, "position": [0.3, 0.3], "velocity": [ 1, 1] } +{ "task": "release", "galaxy_id": 1, "user_id": 1, "position": [0.7, 0.3], "velocity": [-1, 1] } +{ "task": "release", "galaxy_id": 0, "user_id": 2, "position": [0.3, 0.7], "velocity": [ 1, -1] } +{ "task": "release", "galaxy_id": 1, "user_id": 3, "position": [0.7, 0.7], "velocity": [-1, -1] } +{ "task": "report" } +