diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f992edc --- /dev/null +++ b/.gitignore @@ -0,0 +1,143 @@ +################################################################################ +## Custom ## +################################################################################ + +*/md-gui/*/Makefile +*/md-gui/*/md-gui + +################################################################################ +## Qt ## +################################################################################ + +# C++ objects and libs + +*.slo +*.lo +*.o +*.a +*.la +*.lai +*.so +*.dll +*.dylib + +# Qt-es + +/.qmake.cache +/.qmake.stash +*.pro.user +*.pro.user.* +*.qbs.user +*.qbs.user.* +*.moc +moc_*.cpp +qrc_*.cpp +ui_*.h +# Makefile* +*build-* + +# QtCreator + +*.autosave + +# QtCtreator Qml +*.qmlproject.user +*.qmlproject.user.* + +# QtCtreator CMake +CMakeLists.txt.user* + +################################################################################ +## C ## +################################################################################ + +# Prerequisites +*.d + +# Object files +*.o +*.ko +*.obj +*.elf + +# Linker output +*.ilk +*.map +*.exp + +# Precompiled Headers +*.gch +*.pch + +# Libraries +*.lib +*.a +*.la +*.lo + +# Shared objects (inc. Windows DLLs) +*.dll +*.so +*.so.* +*.dylib + +# Executables +*.exe +*.out +*.app +*.i*86 +*.x86_64 +*.hex +*.x + +# Debug files +*.dSYM/ +*.su +*.idb +*.pdb +*.out.* + +# Kernel Module Compile Results +*.mod* +*.cmd +modules.order +Module.symvers +Mkfile.old +dkms.conf + +################################################################################ +## C++ ## +################################################################################ + +# Prerequisites +*.d + +# Compiled Object files +*.slo +*.lo +*.o +*.obj + +# Precompiled Headers +*.gch +*.pch + +# Compiled Dynamic libraries +*.so +*.dylib +*.dll + +# Fortran module files +*.mod +*.smod + +# Compiled Static libraries +*.lai +*.la +*.a +*.lib + +# Executables +*.exe +*.out +*.app \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..6339e6b --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2017 Ruben Felgenhauer, Leonhard Reichenbach + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..6d30dda --- /dev/null +++ b/README.md @@ -0,0 +1,4 @@ +# molecular-dynamics +Molecular dynamics simulation using the Lennard Jones potential + +Authors: Ruben Felgenhauer and Leonhard Reichenbach \ No newline at end of file diff --git a/md-core/md-core.c b/md-core/md-core.c new file mode 100644 index 0000000..b9e28e9 --- /dev/null +++ b/md-core/md-core.c @@ -0,0 +1,473 @@ +/******************************************************************************/ +/* */ +/* Molecular dynamics */ +/* ================== */ +/* */ +/* Copyright (c) 2017 Ruben Felgenhauer, Leonhard Reichenbach */ +/* */ +/* This file is released under the MIT license. */ +/* */ +/******************************************************************************/ + +#include "md-core.h" + +typedef struct { + SimParams *params; + SimData *data; + uint64_t first_k, last_k; +} calculate_forces_targs; + +typedef struct { + SimParams *params; + SimData *data; + uint64_t first_i, last_i; +} apply_forces_targs; + +void seed() { + struct timeval time; + gettimeofday(&time, NULL); + srand48(((unsigned long long)time.tv_sec * 1000000) + time.tv_usec); +} + +/** + * The Lennard Jones potential between two molecules + * @param r the distance between the two molecules + * @return the resulting potential + */ +static double lennjo_potential(double r) { + return 4 * (1/pow(r,12) - 1/pow(r,6)); +} + +/** + * The force that gets induced by the Lennard jones potential + * @param r the distance between the two molecules + * @return The resulting force + */ +static double lennjo_force(double r) { + return 24 * (2/pow(r,13) - 1/pow(r,7)); +} + +/** + * Returns a vector from the given coordinates (that also contains the length + * of the vector). + * @param x the x coordinate + * @param y the y coordinate + * @return the resulting vector + */ +static Vector build_vector(double x, double y) { + Vector result; + result.coordinates.x = x; + result.coordinates.y = y; + result.length = sqrt(x*x + y*y); + return result; +} + +/** + * Determines the distance between two molecules. + * @param first the first position + * @param second the second position + * @param L the length of the square distance + * @param periodic_boundaries whether to use periodic boundaries + * @return the distance vector + */ +static Vector distance(const Coordinates *first, const Coordinates *second, + SimParams *params) { + double dx = second->x - first->x; + double dy = second->y - first->y; + if (params->periodic_boundaries) { + double L = params->L; + if (fabs(dx) > L / 2) { + dx = dx - copysign(1.0, dx) * L; + } + if (fabs(dy) > L / 2) { + dy = dy - copysign(1.0, dy) * L; + } + } + return build_vector(dx, dy); +} + +/** + * Gathers the kinetic energy, potential energy, total energy and temperature + * of the system and writes that data back into their corresponding members + * of data. + * @param data The simulation data + * @param params The simulation parameters + */ +void get_statistics(SimData *data, SimParams *params) { + double Epot = 0.0; + double Ekin = 0.0; + for (uint64_t i=0; i < params->N; i++) { + for (uint64_t j=i+1; j < params->N; j++) { + Vector dist = distance(&(data->molecules[i].curr_pos), + &(data->molecules[j].curr_pos), params); + if(params->dist_threshold == 0.0 || dist.length <= params->dist_threshold){ + Epot += lennjo_potential(dist.length); + } + } + Ekin += (data->molecules[i].vel.x * data->molecules[i].vel.x + + data->molecules[i].vel.y * data->molecules[i].vel.y) / 2; + } + data->kinetic_energy = Ekin; + data->potential_energy = Epot; + data->energy = Ekin + Epot; + data->temperature = Ekin / params->N; +} + +/** + * Initializes the molecules array + * @param params the simulation parameters to use + * @return the molecules + */ +static Molecule *init_molecules(SimParams *params) { + Molecule *molecules = malloc(params->N * sizeof(Molecule)); + ASSERT(molecules, "Could not initialize molecules"); + uint64_t grid_size = ceil(sqrt(params->N)); + double grid_dist = params->L / ((double)grid_size); + + for (uint64_t i = 0; i < params->N; i++) { + double x_curr = ((((double)(i % grid_size)) + 0.5) + + params->max_deviation * (drand48() - 0.5) * sqrt(2)) * grid_dist; + double y_curr = ((((double)(i / grid_size)) + 0.5) + + params->max_deviation * (drand48() - 0.5) * sqrt(2)) * grid_dist; + double v_x = params->max_v0 * (drand48() - 0.5) * sqrt(2); + double v_y = params->max_v0 * (drand48() - 0.5) * sqrt(2); + double x_prev = x_curr - v_x * params->timestep; + double y_prev = y_curr - v_y * params->timestep; + Molecule molecule; + molecule.curr_pos.x = x_curr; + molecule.curr_pos.y = y_curr; + molecule.prev_pos.x = x_prev; + molecule.prev_pos.y = y_prev; + molecule.vel.x = v_x; + molecule.vel.y = v_y; + molecules[i] = molecule; + } + return molecules; +} + +/** + * Thread function for calculate_forces + */ +static void *calculate_forces_tfun(void* _args) { + calculate_forces_targs *args = (calculate_forces_targs*) _args; + for (uint64_t k = args->first_k; k <= args->last_k; k++) { + uint64_t i = args->data->index_mappings[0][k]; + uint64_t j = args->data->index_mappings[1][k]; + Vector dist = distance(&(args->data->molecules[i].curr_pos), + &(args->data->molecules[j].curr_pos), + args->params); + + Coordinates *force_ij = &(args->data->forces_buffer[i][j]); + Coordinates *force_ji = &(args->data->forces_buffer[j][i]); + + if(dist.length > 0.0 && (args->params->dist_threshold == 0.0 + || dist.length <= args->params->dist_threshold)){ + double force = lennjo_force(dist.length); + double force_x = force * dist.coordinates.x / dist.length; + double force_y = force * dist.coordinates.y / dist.length; + force_ij->x = force_x; + force_ij->y = force_y; + force_ji->x = -force_x; + force_ji->y = -force_y; + } else { + force_ij->x = 0.0; + force_ij->y = 0.0; + force_ji->x = 0.0; + force_ji->y = 0.0; + } + } + return NULL; +} + +/** + * Calculates all forces between all molecules and stores them in the forces + * buffer. + * @param data the simulation data with the molecules array and the forces buffer + * @param params the simulation parameters + */ +static void calculate_forces(SimData *data, SimParams *params) { + ASSERT(params->number_of_threads, "At least one thread needed."); + if (params->N > 1) { + pthread_t threads[params->number_of_threads]; + uint64_t number_of_forces = params->N * (params->N - 1) / 2; + uint64_t k_per_thread = number_of_forces / params->number_of_threads; + calculate_forces_targs args[params->number_of_threads]; + for(uint64_t t = 0; t < params->number_of_threads; t++){ + args[t].data = data; + args[t].params = params; + args[t].first_k = t * k_per_thread; + args[t].last_k = (t == params->number_of_threads - 1) ? number_of_forces - 1 + : (t + 1) * k_per_thread - 1; + + ASSERT(!pthread_create(&threads[t], NULL, &calculate_forces_tfun, &args[t]), + "Failed to create a new thread"); + } + for(uint64_t t = 0; t < params->number_of_threads; t++){ + pthread_join(threads[t], NULL); + } + } +} + +/** + * Returns a helper array that contains the mappings of an index k on the + * flattened array to an index i and an index j on the upper right triangular + * matrix with i,j=0..N-1. + * @param N + * @return The array of array of indices. The first element is the array of + * mappings from k to i, and the second element is the array of mappings + * from k to j. + * Example: Let mappings = index_mappings(10); + * => i_of_k = mappings[0][k] + * => j_of_k = mappings[1][k] + */ +static uint64_t **get_index_mappings(uint64_t N) { + /* For N particles, we only need to calculate N*(N-1)/2 forces, because + F_ij = -F_ji and F_ii = 0. We save two consecutive arrays. */ + uint64_t **result = malloc(sizeof(uint64_t*) * 2); + ASSERT(result, "Could not allocate memory for index mappings."); + result[0] = malloc(sizeof(uint64_t) * N * (N - 1) / 2); + ASSERT(result[0], "Could not allocate memory for index mappings."); + result[1] = malloc(sizeof(uint64_t) * N * (N - 1) / 2); + ASSERT(result[1], "Could not allocate memory for index mappings."); + uint64_t k = 0; + for (uint64_t i = 0; i < N-1; i++) { + for (uint64_t j = i + 1; j < N; j++, k++) { + result[0][k] = i; + result[1][k] = j; + } + } + return result; +} + +/** + * Calculates the total force F_i that affects a particle i. This is just the sum + * of all forces F_j,i that act on a particle. + * @param data the simulation data + * @param params the simulation params + * @param i The index of the particle to get the force for. + * @return the resulting force. + */ +static Coordinates get_total_force(SimData *data, SimParams *params, uint64_t i) { + Coordinates result = {.x = 0.0, .y = 0.0}; + for (uint64_t j = 0; j < params->N; j++) { + result.x += data->forces_buffer[j][i].x; + result.y += data->forces_buffer[j][i].y; + } + return result; +} + +/** + * Corrects a position so that 0 <= position <= L. + * @param curr the current position that is going to be positioned the same way + * relatively to next that it was before the correction was applies. This + * might include putting curr on the other side of next with the same + * distance if the movement of direction is being flipped during + * elastic reflection (if periodic_boundaries == false). + * @param next the next position (the one to correct). If periodic_boundaries, + * next will be teleported to the other side of the lattice. Otherwise, + * it will be reflected elastically. + * @param params the simulation params, including L and periodic_boundaries. + */ +static void fix_boundaries(double *curr, double *next, SimParams *params) { + double L = params->L; + if (*next > L || *next < 0) { + // We'll need this to correct the current position later + double curr_to_next = *next - *curr; + if (params->periodic_boundaries) { + if (*next > L) { + // fmod should return a value between 0.0 and L here. + *next = fmod(*next, L); + } else { + // fmod should return a value between -L and 0.0 here, so position should + // mathematically be between 0.0 and and L, but numerical errors do happen. + *next = L + fmod(*next, L); + // The >= is there to catch numerical errors. The distance to L should be + // at the order of magnitude of machine accuracy. Position can not be greater + // than L mathematically at this point. + if (*next >= L) { + *next = 0.0; + } + } + } else { /* Reflective walls */ + double dist_to_border = *next > L ? L - *curr : *curr; + // The distance that remains after the first collision + double rem_initial = fabs(curr_to_next) - dist_to_border; + // The distance that remains after the last collision, if there is going + // to be more than one, according to the velocity. + double rem_final = fmod(rem_initial, L); + // We'll need to turn the direction of movement around, if the particle + // reflects an odd amount of times with any walls. + bool keep_direction = (bool)((int)((rem_initial - rem_final) / L) % 2); + // Determine at which border the particle is going to be placed + if (keep_direction == (*next > L)) { + *next = rem_final; + } else { + *next = L - rem_final; + } + // Determine on which side curr is going to be placed + if (!keep_direction) { + curr_to_next *= -1; + } + } + // Correct curr. + *curr = *next - curr_to_next; + } +} + + +/** + * Thread function for apply_forces + */ +static void *apply_forces_tfun(void* _args){ + apply_forces_targs *args = (apply_forces_targs*) _args; + double squared_timestep = args->params->timestep * args->params->timestep; + for(uint64_t i = args->first_i; i <= args->last_i; i++) { + + Coordinates force = get_total_force(args->data, args->params, i); + + Coordinates *prev_pos = &(args->data->molecules[i].prev_pos); + Coordinates *curr_pos = &(args->data->molecules[i].curr_pos); + + Coordinates next_pos = {.x = 2 * curr_pos->x - prev_pos->x + + force.x * squared_timestep, + .y = 2 * curr_pos->y - prev_pos->y + + force.y * squared_timestep}; + + args->data->molecules[i].vel.x = (next_pos.x - prev_pos->x) + / (2 * args->params->timestep); + args->data->molecules[i].vel.y = (next_pos.y - prev_pos->y) + / (2 * args->params->timestep); + + fix_boundaries(&(curr_pos->x), &(next_pos.x), args->params); + fix_boundaries(&(curr_pos->y), &(next_pos.y), args->params); + + *prev_pos = *curr_pos; + *curr_pos = next_pos; + + } + return NULL; +} + +/** + * Applies the stored forces to the molecules. + * @param data the simulation data + * @param params the simulation parameters + */ +static void apply_forces(SimData *data, SimParams *params) { + ASSERT(params->number_of_threads, "At least one thread needed."); + pthread_t threads[params->number_of_threads]; + uint64_t number_of_molecules = params->N; + uint64_t k_per_thread = number_of_molecules / params->number_of_threads; + apply_forces_targs args[params->number_of_threads]; + for (uint64_t t = 0; t < params->number_of_threads; t++) { + args[t].data = data; + args[t].params = params; + args[t].first_i = t * k_per_thread; + args[t].last_i = (t == params->number_of_threads - 1) ? number_of_molecules - 1 + : (t + 1) * k_per_thread - 1; + ASSERT(!pthread_create(&threads[t], NULL, &apply_forces_tfun, &args[t]), + "Failed to create a new thread"); + } + for (uint64_t t = 0; t < params->number_of_threads; t++) { + pthread_join(threads[t], NULL); + } +} + +void enable_heat_bath(SimData *data, double target_temperature, uint64_t steps) { + ASSERT(steps, "Steps must be greater than 0"); + + double alpha_tilde = 3.0; + HeatBath heat_bath; + heat_bath.alpha_tilde = alpha_tilde; + heat_bath.steps_to_the_alpha_tilde = pow(steps, alpha_tilde); + heat_bath.steps = steps; + heat_bath.current_step = 1; + heat_bath.target_temperature = target_temperature; + + data->heat_bath = heat_bath; + data->heat_bath_enabled = true; +} + +void multiply_velocity(double *curr_pos, double *prev_pos, double *vel, double factor) { + *prev_pos = *curr_pos - (*curr_pos - *prev_pos) * factor; + *vel *= factor; +} + +void apply_heat_bath(SimData *data, SimParams *params) { + HeatBath *heat_bath = &(data->heat_bath); + + double foo1 = pow(heat_bath->current_step, heat_bath->alpha_tilde); + double foo2 = foo1 / heat_bath->steps_to_the_alpha_tilde; + double foo3 = heat_bath->target_temperature / data->temperature; + double foo4 = pow(foo3, foo2); + + for (uint64_t i = 0; i < params->N; i++) { + Coordinates *prev_pos = &(data->molecules[i].prev_pos); + Coordinates *curr_pos = &(data->molecules[i].curr_pos); + Coordinates *vel = &(data->molecules[i].vel); + multiply_velocity(&(curr_pos->x), &(prev_pos->x), &(vel->x), foo4); + multiply_velocity(&(curr_pos->y), &(prev_pos->y), &(vel->y), foo4); + } + if (++(heat_bath->current_step) > heat_bath->steps) { + data->heat_bath_enabled = false; + } +} + +void step(SimData *data, SimParams *params) { + calculate_forces(data, params); + apply_forces(data, params); + get_statistics(data, params); + + if (data->heat_bath_enabled) { + apply_heat_bath(data, params); + } +} + +SimData init_data(SimParams *params) { + SimData result; + result.molecules = init_molecules(params); + result.index_mappings = get_index_mappings(params->N); + result.forces_buffer = malloc(sizeof(Coordinates*) * params->N); + ASSERT(result.forces_buffer, "Could not allocate memory for forces buffer"); + + for (uint64_t i = 0; i < params->N; i++) { + result.forces_buffer[i] = malloc(sizeof(Coordinates) * params->N); + ASSERT(result.forces_buffer[i], "Could not allocate memory for forces buffer"); + result.forces_buffer[i][i].x = 0.0; + result.forces_buffer[i][i].y = 0.0; + } + + result.heat_bath_enabled = false; + + return result; +} + +SimParams init_params(uint64_t number_of_threads, uint64_t N, + double L, double timestep, double max_deviation, + double max_v0, bool periodic_boundaries, double dist_threshold, + uint64_t iterations) { + SimParams result; + result.number_of_threads = number_of_threads; + result.N = N; + result.L = L; + result.timestep = timestep; + result.max_deviation = max_deviation; + result.max_v0 = max_v0; + result.periodic_boundaries = periodic_boundaries; + result.dist_threshold = dist_threshold; + result.iterations = iterations; + return result; +} + +void finalize(SimData *data, SimParams *params) { + free(data->molecules); + free(data->index_mappings[0]); + free(data->index_mappings[1]); + free(data->index_mappings); + for (uint64_t i = 0; i < params->N; i++) { + free(data->forces_buffer[i]); + } + free(data->forces_buffer); +} + + diff --git a/md-core/md-core.h b/md-core/md-core.h new file mode 100644 index 0000000..ddda733 --- /dev/null +++ b/md-core/md-core.h @@ -0,0 +1,145 @@ +/******************************************************************************/ +/* */ +/* Molecular dynamics */ +/* ================== */ +/* */ +/* Copyright (c) 2017 Ruben Felgenhauer, Leonhard Reichenbach */ +/* */ +/* This file is released under the MIT license. */ +/* */ +/******************************************************************************/ + +#ifndef MDCORE_H +#define MDCORE_H + +#include +#include +#include +#include +#include +#include +#include +#include + +#define ASSERT(COND, MSG)\ + if(!(COND)){\ + fprintf(stderr,"Error: \"%s\" in %s, line:%d\n", (MSG),__FILE__, __LINE__);\ + exit(EXIT_FAILURE);\ + } + +typedef struct { + double x; + double y; +} Coordinates; + +/** + Struct for a molecule, describing its position and velocity +*/ +typedef struct { + Coordinates curr_pos; /**< The current position */ + Coordinates prev_pos; /**< The previous position */ + Coordinates vel; /**< The (current) velocity */ +} Molecule; + +typedef struct { + double target_temperature; + uint64_t steps; + uint64_t current_step; + double alpha_tilde; + double steps_to_the_alpha_tilde; +} HeatBath; + +typedef struct { + Molecule *molecules; /**< The array of molecules */ + uint64_t **index_mappings; /**< The 2d-array of index mappings */ + Coordinates **forces_buffer; /**< The buffer to store the forces inside */ + double kinetic_energy; /**< The total kinetic energy of the system */ + double potential_energy; /**< The total potential energy of the system */ + double energy; /**< The energy of the system = E_kin + E_pot */ + double temperature; /**< The temperature of the system */ + HeatBath heat_bath; + bool heat_bath_enabled; +} SimData; + +typedef struct { + uint64_t number_of_threads; /**< The number of threads to use */ + uint64_t N; /**< The number of molecules */ + double L; /**< The width of the square lattice */ + double timestep; /**< The timestep */ + double max_deviation; /**< The maximum deviation of the molecules' positions */ + double max_v0; /**< The maximum initial velocity of the molecules */ + bool periodic_boundaries; /**< Whether to use periodic boundaries */ + double dist_threshold; /**< The max distance to still calculate forces */ + uint64_t iterations; /**< unused */ +} SimParams; + +typedef struct { + Coordinates coordinates; + double length; +} Vector; + + + +/** + * Seeds the drand48, erand48, jrand48, lrand48, mrand48, nrand48 methods + * for pseudo-random number generation with micro-time. + * Only works on POSIX systems. + */ +void seed(); + +/** + * Initializes all simulation data (molecules, forces buffer, and index mappings) + * @param params the simulation parameters + * @return the simulation data + */ +SimData init_data(SimParams *params); + +/** + * Initializes the simulation parameters with the given values. + * @param number_of_threads the number of threads to use + * @param N the number of molecules + * @param L the width of the square lattice + * @param timestep the timestep + * @param max_deviation the maximum deviation of the molecules' positions + * @param max_v0 the maximum initial velocity of the molecules + * @param periodic_boundaries whether to use periodic boundaries + * @param dist_threshold the maximum distance at which forces get calculated + * @param iterations unused param + * @return a structure which contains all above parameters + */ +SimParams init_params(uint64_t number_of_threads, uint64_t N, + double L, double timestep, double max_deviation, + double max_v0, bool periodic_boundaries, double dist_threshold, + uint64_t iterations); + +/** + Frees all the allocated resources from initalize. +*/ + +/** + * Frees all the resources that have been allocated at init_data + * @param data the simulation data to delete + * @param params the simulation parameters + */ +void finalize(SimData *data, SimParams *params); + +/** + * Do one simulation step: + * 1) Calculate the forces and store them in the forces buffer + * 2) Load the forces and apply them to the molecules + * @param data the simulation data with molecules ans forces buffer + * @param params the simulatiom params to use + */ +void step(SimData *data, SimParams *params); + +/** + * Enables a heat bath with the given arguments for the simulation + * @param data the simulation data + * @param target_temperature the temperature to adjust the system to + * @param steps the number of steps to use + * @param attack_coefficient The attack coefficient -1 < alpha < 1 + */ +void enable_heat_bath(SimData *data, double target_temperature, uint64_t steps); + + +#endif // MDCORE_H diff --git a/md-gui/3rd-party-licenses/GPLv3 b/md-gui/3rd-party-licenses/GPLv3 new file mode 100644 index 0000000..9cecc1d --- /dev/null +++ b/md-gui/3rd-party-licenses/GPLv3 @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + {one line to give the program's name and a brief idea of what it does.} + Copyright (C) {year} {name of author} + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + {project} Copyright (C) {year} {fullname} + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/md-gui/3rd-party-licenses/LGPLv3 b/md-gui/3rd-party-licenses/LGPLv3 new file mode 100644 index 0000000..65c5ca8 --- /dev/null +++ b/md-gui/3rd-party-licenses/LGPLv3 @@ -0,0 +1,165 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. diff --git a/md-gui/src/main.cpp b/md-gui/src/main.cpp new file mode 100644 index 0000000..eb00def --- /dev/null +++ b/md-gui/src/main.cpp @@ -0,0 +1,45 @@ +/******************************************************************************/ +/* */ +/* Molecular dynamics */ +/* ================== */ +/* */ +/* Copyright (c) 2017 Ruben Felgenhauer, Leonhard Reichenbach */ +/* */ +/* This file is released under the MIT license, but is made to be used with */ +/* the Qt Framework, which is released under the GNU Lesser General Public */ +/* License (LGPL) and partly under the GNU General Public License (GPL). */ +/* */ +/******************************************************************************/ + +#include "mainwindow.h" +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + + uint64_t number_of_threads = 1; + uint64_t N = 25; + double L = 5.0; + double timestep = 0.005; + double max_deviation = 0.0001; + double max_v0 = 0.000; + bool periodic_boundaries = true; + double dist_threshold = 3.0; + + SimParams sim_params = init_params(number_of_threads, N, L, timestep, max_deviation, + max_v0, periodic_boundaries, dist_threshold, 0); + + DisplayOptions display_options = {.frameskip = 0, + .dist_threshold_indicator_enabled = false, + .dist_threshold_color = Qt::blue, + .sigma_indicator_enabled = false, + .sigma_color = Qt::red, + .particle_size = 10, + .update_interval = 1.0}; + + MainWindow w(NULL, sim_params, display_options); + w.show(); + + return a.exec(); +} diff --git a/md-gui/src/mainwindow.cpp b/md-gui/src/mainwindow.cpp new file mode 100644 index 0000000..fc02582 --- /dev/null +++ b/md-gui/src/mainwindow.cpp @@ -0,0 +1,489 @@ +/******************************************************************************/ +/* */ +/* Molecular dynamics */ +/* ================== */ +/* */ +/* Copyright (c) 2017 Ruben Felgenhauer, Leonhard Reichenbach */ +/* */ +/* This file is released under the MIT license, but is made to be used with */ +/* the Qt Framework, which is released under the GNU Lesser General Public */ +/* License (LGPL) and partly under the GNU General Public License (GPL). */ +/* */ +/******************************************************************************/ + +#include "mainwindow.h" +#include "ui_mainwindow.h" + +MainWindow::MainWindow(QWidget *parent) : + QMainWindow(parent), + ui(new Ui::MainWindow) +{ + ui->setupUi(this); + rescaleUi(); +} + +MainWindow::MainWindow(QWidget *parent, SimParams sim_params, DisplayOptions display_options) : + QMainWindow(parent), + ui(new Ui::MainWindow) +{ + this->sim_params = sim_params; + this->display_options = display_options; + + seed(); + + this->sim_data = init_data(&sim_params); + + gettimeofday(&(this->before_step), NULL); + gettimeofday(&(this->after_step), NULL); + + ui->setupUi(this); + + this->set_ui_bindings(); + + ui->sbox_num_threads->setValue(this->sim_params.number_of_threads); + ui->sbox_num_particles->setValue(this->sim_params.N); + ui->sbox_lattice_len->setValue(this->sim_params.L); + ui->sbox_timestep->setValue(this->sim_params.timestep); + ui->sbox_max_deviation->setValue(this->sim_params.max_deviation); + ui->sbox_max_v0->setValue(this->sim_params.max_v0); + ui->cbox_periodic_boundaries->setChecked(this->sim_params.periodic_boundaries); + ui->sbox_dist_threshold->setValue(this->sim_params.dist_threshold); + + ui->sbox_frameskip->setValue(this->display_options.frameskip); + ui->cbox_dist_threshold->setChecked( + this->display_options.dist_threshold_indicator_enabled); + ui->cbox_sigma->setChecked(this->display_options.sigma_indicator_enabled); + + QFrame *frame; QPalette palette; + frame = ui->frm_dist_threshold_col; + palette = frame->palette(); + palette.setColor(QPalette::Window, this->display_options.dist_threshold_color); + frame->setPalette(palette); + frame = ui->frm_sigma_col; + palette = frame->palette(); + palette.setColor(QPalette::Window, this->display_options.sigma_color); + frame->setPalette(palette); + + ui->sbox_particle_size->setValue(this->display_options.particle_size); + ui->sbox_stat_update->setValue(this->display_options.update_interval); + + //this->print(); + +} + +void MainWindow::set_ui_bindings() { + std::vector plus_buttons = {this->ui->btn_num_threads_p, + this->ui->btn_num_particles_p, + this->ui->btn_lattice_len_p, + this->ui->btn_timestep_p, + this->ui->btn_max_deviation_p, + this->ui->btn_max_v0_p, + this->ui->btn_dist_threshold_p, + this->ui->btn_frameskip_p, + this->ui->btn_particle_size_p, + this->ui->btn_stat_update_p, + this->ui->btn_target_temp_p, + this->ui->btn_heat_time_p/*, + this->ui->btn_attack_coeff_p*/}; + std::vector minus_buttons = {this->ui->btn_num_threads_m, + this->ui->btn_num_particles_m, + this->ui->btn_lattice_len_m, + this->ui->btn_timestep_m, + this->ui->btn_max_deviation_m, + this->ui->btn_max_v0_m, + this->ui->btn_dist_threshold_m, + this->ui->btn_frameskip_m, + this->ui->btn_particle_size_m, + this->ui->btn_stat_update_m, + this->ui->btn_target_temp_m, + this->ui->btn_heat_time_m/*, + this->ui->btn_attack_coeff_m*/}; + for(auto it=plus_buttons.begin() ; it < plus_buttons.end(); it++ ) { + connect(*it, SIGNAL(pressed()), this, SLOT(increment_spinbox())); + connect(*it, SIGNAL(released()), this, SLOT(focus_spinbox())); + } + for(auto it=minus_buttons.begin() ; it < minus_buttons.end(); it++ ) { + connect(*it, SIGNAL(pressed()), this, SLOT(decrement_spinbox())); + connect(*it, SIGNAL(released()), this, SLOT(focus_spinbox())); + } + + connect(this->ui->btn_num_particles_mm, SIGNAL(pressed()), + this, SLOT(prev_sqr_spinbox())); + connect(this->ui->btn_num_particles_mm, SIGNAL(released()), + this, SLOT(focus_spinbox())); + connect(this->ui->btn_num_particles_pp, SIGNAL(pressed()), + this, SLOT(next_sqr_spinbox())); + connect(this->ui->btn_num_particles_pp, SIGNAL(released()), + this, SLOT(focus_spinbox())); + + connect(this->ui->btn_dist_threshold_col, SIGNAL(clicked()), + this, SLOT(set_frm_color())); + connect(this->ui->btn_sigma_col, SIGNAL(clicked()), + this, SLOT(set_frm_color())); +} + +MainWindow::~MainWindow() +{ + this->do_step = false; + finalize(&(this->sim_data), &(this->sim_params)); + delete ui; +} + +void MainWindow::print() { + for (size_t i = 0; i < sim_params.N; i++) { + printf(/*foo, */"i=%0ld:\t%.5g\t%.5g\n", i, + this->sim_data.molecules[i].curr_pos.x, + this->sim_data.molecules[i].curr_pos.y); + } +} + +void MainWindow::rescaleUi() { + int height = this->ui->cont_lvl2_1->height(); + int width = this->ui->cont_lvl2_1->width(); + if (height > width) { + this->ui->spacer_draw_area_left->setMaximumWidth(0); + this->ui->spacer_draw_area_right->setMaximumWidth(0); + this->ui->spacer_draw_area_top->setMaximumHeight((height-width)/2); + this->ui->spacer_draw_area_bottom->setMaximumHeight((height-width)/2); + } else { + this->ui->spacer_draw_area_left->setMaximumWidth((width-height)/2); + this->ui->spacer_draw_area_right->setMaximumWidth((width-height)/2); + this->ui->spacer_draw_area_top->setMaximumHeight(0); + this->ui->spacer_draw_area_bottom->setMaximumHeight(0); + } +} + +void MainWindow::step_ui() { + struct timeval temp; + struct timeval start_to_start; + struct timeval start_to_end; + + gettimeofday(&temp, NULL); + timersub(&temp, &(this->before_step), &start_to_start); + this->before_step = temp; + + for (int i = 0; i <= this->display_options.frameskip; i++) { + step(&sim_data, &sim_params); + } + + gettimeofday(&(this->after_step), NULL); + + timersub(&after_step, &before_step, &start_to_end); + + //this->print(); + + this->repaint(); + + double start_to_start_seconds = (double)start_to_start.tv_sec + + (((double)start_to_start.tv_usec) / 1000000); + + double start_to_end_seconds = (double)start_to_end.tv_sec + + (((double)start_to_end.tv_usec) / 1000000); + + this->update_counter += start_to_start_seconds; + if (this->update_counter > this->display_options.update_interval) { + this->update_counter = 0.0; + + this->energies.push_back(this->sim_data.energy); + if (energies.size() > 1024) { + energies.erase(energies.begin()); + } + + this->temperatures.push_back(this->sim_data.temperature); + if (temperatures.size() > 1024) { + temperatures.erase(temperatures.begin()); + } + + this->ui->lbl_calc_time->setText("Calculation time: " + + QString::number(start_to_end_seconds*1000000, 'f', 0) + + " µs "); + + this->ui->lbl_frame_time->setText("Frame time: " + + QString::number(start_to_start_seconds*1000000, 'f', 0) + + " µs"); + + this->ui->lbl_frame_rate->setText("Refresh rate: " + + QString::number(1/start_to_start_seconds, 'f', 1) + + " fps"); + } + + this->ui->btn_heat_apply->setEnabled(!this->sim_data.heat_bath_enabled); + this->ui->btn_heat_abort->setEnabled(this->sim_data.heat_bath_enabled); + +} + +QRect MainWindow::getRect(QFrame *frame) { + int width = frame->contentsRect().width(); + int height = frame->contentsRect().height(); + int x = 0; + int y = 0; + QWidget *widget = frame; + while (widget != (QWidget*)(this)) { + x += widget->x(); + y += widget->y(); + widget = widget->parentWidget(); + } + return QRect(x,y,width,height); +} + +void MainWindow::drawSimulation() { + QFrame *canvas = this->ui->draw_area; + QRect canvasRect = getRect(canvas); + + QPainter painter(this); + painter.setClipping(true); + painter.setClipRect(canvasRect); + painter.fillRect(painter.clipBoundingRect(), Qt::white); + + QPen pointpen(Qt::black); + pointpen.setWidth(this->display_options.particle_size); + pointpen.setCapStyle(Qt::RoundCap); + + QPen circlepen(this->display_options.dist_threshold_color); + circlepen.setCapStyle(Qt::RoundCap); + circlepen.setWidth(2); + + QPen smallcirclepen(this->display_options.sigma_color); + circlepen.setCapStyle(Qt::RoundCap); + circlepen.setWidth(2); + + for (size_t i = 0; i < sim_params.N; i++) { + QPoint p; + + int x = std::ceil((double)(canvasRect.left()) + (double)(canvasRect.width()) + * (this->sim_data.molecules[i].curr_pos.x) + / ((double)(this->sim_params.L))); + + int y = std::ceil((double)(canvasRect.top()) + (double)(canvasRect.height()) + * (this->sim_data.molecules[i].curr_pos.y) + / ((double)(this->sim_params.L))); + + p.setX(x); + p.setY(y); + + painter.setPen(pointpen); + painter.drawPoint(p); + + if (display_options.sigma_indicator_enabled) { + painter.setPen(smallcirclepen); + int r = std::ceil(((double)(canvasRect.width())) / + ((double)(this->sim_params.L))); + painter.drawEllipse(p, r, r); + } + + if (display_options.dist_threshold_indicator_enabled) { + painter.setPen(circlepen); + int r = std::ceil(((double)(canvasRect.width())) * + this->sim_params.dist_threshold / + ((double)(this->sim_params.L))); + painter.drawEllipse(p, r, r); + } + } +} + +void MainWindow::drawGraph(QFrame *canvas, std::vector values, + const QString &label) { + QRect canvasRect = getRect(canvas); + QPainter painter(this); + painter.setClipping(true); + painter.setClipRect(canvasRect); + painter.fillRect(painter.clipBoundingRect(), Qt::white); + + if (!values.empty()) { + QPen linepen(Qt::black); + QPen pointpen(Qt::black); + pointpen.setCapStyle(Qt::RoundCap); + pointpen.setWidth(5); + + double max_value = *(std::max_element(values.begin(), values.end())); + double min_value = *(std::min_element(values.begin(), values.end())); + + int right = canvasRect.right() - 215; + int bottom = canvasRect.top() + canvasRect.height() - 15; + int height = canvasRect.height() - 30; + int width = canvasRect.width(); + int step = 10; + + int i = 0; + QPoint old_point; + QPoint new_point; + for (auto it = values.rbegin(); + it < values.rend() && i * step < width; + it++, i++) { + double value = *it; + int x = right - i * step; + int y = ceil((double)bottom - (value - min_value) * + (double)height / (max_value - min_value)); + if (!i) { + old_point.setX(x); + old_point.setY(y); + painter.setPen(pointpen); + painter.drawPoint(old_point); + painter.setPen(linepen); + painter.drawText(old_point.x()+15,old_point.y(), + label + ": " + QString::number(value, 'g', 4)); + } else { + new_point.setX(x); + new_point.setY(y); + painter.drawLine(old_point, new_point); + old_point.setX(new_point.x()); + old_point.setY(new_point.y()); + } + } + } +} + +void MainWindow::paintEvent(QPaintEvent *) { + rescaleUi(); + + drawSimulation(); + + drawGraph(this->ui->frm_energy_graph, this->energies, "Energy"); + + drawGraph(this->ui->frm_temp_graph, this->temperatures, "Temperature"); +} + +void MainWindow::decrement_spinbox() { + QAbstractSpinBox *spinbox = ((QPushButton *)(sender()))->parentWidget() + ->findChild(); + QSpinBox *_spinbox = qobject_cast(spinbox); + if (_spinbox) { + _spinbox->setValue(_spinbox->value() - _spinbox->singleStep()); + } else { + QDoubleSpinBox *_spinbox = qobject_cast(spinbox); + _spinbox->setValue(_spinbox->value() - _spinbox->singleStep()); + } +} + +void MainWindow::increment_spinbox() { + QAbstractSpinBox *spinbox = ((QPushButton *)(sender()))->parentWidget() + ->findChild(); + QSpinBox *_spinbox = qobject_cast(spinbox); + if (_spinbox) { + _spinbox->setValue(_spinbox->value() + _spinbox->singleStep()); + } else { + QDoubleSpinBox *_spinbox = qobject_cast(spinbox); + _spinbox->setValue(_spinbox->value() + _spinbox->singleStep()); + } +} + +void MainWindow::prev_sqr_spinbox() { + QSpinBox *spinbox = ((QPushButton *)(sender()))->parentWidget() + ->findChild(); + int temp = (ceil(sqrt((double)spinbox->value()))-1); + spinbox->setValue(temp*temp); +} + +void MainWindow::next_sqr_spinbox() { + QSpinBox *spinbox = ((QPushButton *)(sender()))->parentWidget() + ->findChild(); + int temp = (floor(sqrt((double)spinbox->value()))+1); + spinbox->setValue(temp*temp); +} + +void MainWindow::focus_spinbox() { + QPushButton *_sender = (QPushButton *)sender(); + if (!_sender->isDown()) { + QAbstractSpinBox *spinbox = _sender->parentWidget() + ->findChild(); + spinbox->setFocus(); + } +} + +void MainWindow::set_frm_color() { + QFrame *frame = (QFrame *)(((QPushButton*)(sender()))->parentWidget()); + QPalette palette = frame->palette(); + QColor color = QColorDialog::getColor(palette.window().color(), this); + if(color.isValid()) { + palette.setColor(QPalette::Window, color); + } + frame->setPalette(palette); +} + +void MainWindow::on_btn_sim_params_apply_clicked() +{ + finalize(&(this->sim_data), &(this->sim_params)); + this->energies.clear(); + this->temperatures.clear(); + this->sim_params = init_params(ui->sbox_num_threads->value(), + ui->sbox_num_particles->value(), + ui->sbox_lattice_len->value(), + ui->sbox_timestep->value(), + ui->sbox_max_deviation->value(), + ui->sbox_max_v0->value(), + ui->cbox_periodic_boundaries->isChecked(), + ui->sbox_dist_threshold->value(), + 0); + this->sim_data = init_data(&sim_params); + //this->print(); + this->repaint(); +} + +void MainWindow::on_btn_sim_step_clicked() +{ + this->step_ui(); +} + +void MainWindow::on_btn_sim_start_clicked() +{ + this->do_step = true; + this->ui->btn_sim_start->setEnabled(false); + this->ui->btn_sim_stop->setEnabled(true); + this->ui->btn_sim_step->setEnabled(false); + while (this->do_step && this->isVisible()) { + this->step_ui(); + QApplication::processEvents(); + } +} + +void MainWindow::on_btn_sim_stop_clicked() +{ + this->ui->btn_sim_start->setEnabled(true); + this->ui->btn_sim_stop->setEnabled(false); + this->ui->btn_sim_step->setEnabled(true); + this->do_step = false; +} + +void MainWindow::on_btn_display_apply_clicked() +{ + this->display_options.frameskip = this->ui->sbox_frameskip->value(); + this->display_options.dist_threshold_indicator_enabled = this->ui->cbox_dist_threshold->isChecked(); + this->display_options.dist_threshold_color = this->ui->frm_dist_threshold_col->palette().window().color(); + this->display_options.sigma_indicator_enabled = this->ui->cbox_sigma->isChecked(); + this->display_options.sigma_color = this->ui->frm_sigma_col->palette().window().color(); + this->display_options.particle_size = this->ui->sbox_particle_size->value(); + this->display_options.update_interval = this->ui->sbox_stat_update->value(); + this->repaint(); +} + +void MainWindow::on_btn_heat_apply_clicked() +{ + double target_temperature = this->ui->sbox_target_temp->value(); + uint64_t steps = 100 * this->ui->sbox_heat_time->value(); + //double attack_coefficient = this->ui->sbox_attack_coeff->value(); + + enable_heat_bath(&(this->sim_data), target_temperature, steps); + + this->ui->btn_heat_apply->setEnabled(false); + this->ui->btn_heat_abort->setEnabled(true); +} + +void MainWindow::on_btn_heat_abort_clicked() +{ + this->sim_data.heat_bath_enabled = false; + this->ui->btn_heat_apply->setEnabled(true); +} + +void MainWindow::on_btn_help_clicked() +{ + QMessageBox msg; + msg.setInformativeText("Copyright (c) 2017 Ruben Felgenhauer, Leonhard " + "Reichenbach" "\n\n" "This application is released " + "under the MIT license, but is made with the Qt " + "Framework, which is released under the GNU Lesser " + "General Public License (LGPL) and partly under the " + "GNU General Public License (GPL)."); + msg.setText("Molecular dynamics"); + msg.setStandardButtons(QMessageBox::Close); + msg.exec(); +} diff --git a/md-gui/src/mainwindow.h b/md-gui/src/mainwindow.h new file mode 100644 index 0000000..9309e5c --- /dev/null +++ b/md-gui/src/mainwindow.h @@ -0,0 +1,95 @@ +/******************************************************************************/ +/* */ +/* Molecular dynamics */ +/* ================== */ +/* */ +/* Copyright (c) 2017 Ruben Felgenhauer, Leonhard Reichenbach */ +/* */ +/* This file is released under the MIT license, but is made to be used with */ +/* the Qt Framework, which is released under the GNU Lesser General Public */ +/* License (LGPL) and partly under the GNU General Public License (GPL). */ +/* */ +/******************************************************************************/ + +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include + +#include +#include +#include +#include +#include + +extern "C" { + #include "../../md-core/md-core.h" +} + +typedef struct { + int frameskip; + bool dist_threshold_indicator_enabled; + QColor dist_threshold_color; + bool sigma_indicator_enabled; + QColor sigma_color; + int particle_size; + double update_interval; +} DisplayOptions; + +namespace Ui { +class MainWindow; +} + +class MainWindow : public QMainWindow +{ + Q_OBJECT + +public: + explicit MainWindow(QWidget *parent = 0); + MainWindow(QWidget *parent, SimParams sim_params, DisplayOptions display_options); + ~MainWindow(); + void rescaleUi(); + void print(); + void set_ui_bindings(); + SimParams sim_params; + SimData sim_data; + struct timeval before_step; + struct timeval after_step; + bool do_step = false; + double update_counter = 0.0; + void step_ui(); + DisplayOptions display_options; + QRect getRect(QFrame *frame); + void drawSimulation(); + void drawGraph(QFrame *canvas, std::vector values, const QString &label); + std::vector energies; + std::vector temperatures; + +protected: + //void resizeEvent(QResizeEvent *); + void paintEvent(QPaintEvent *); + +private slots: + void increment_spinbox(); + void decrement_spinbox(); + void next_sqr_spinbox(); + void prev_sqr_spinbox(); + void focus_spinbox(); + void set_frm_color(); + void on_btn_sim_params_apply_clicked(); + void on_btn_sim_step_clicked(); + void on_btn_sim_start_clicked(); + void on_btn_sim_stop_clicked(); + void on_btn_display_apply_clicked(); + void on_btn_heat_apply_clicked(); + + void on_btn_heat_abort_clicked(); + + void on_btn_help_clicked(); + +private: + Ui::MainWindow *ui; + +}; + +#endif // MAINWINDOW_H diff --git a/md-gui/src/mainwindow.ui b/md-gui/src/mainwindow.ui new file mode 100644 index 0000000..d52c52e --- /dev/null +++ b/md-gui/src/mainwindow.ui @@ -0,0 +1,2395 @@ + + + MainWindow + + + + 0 + 0 + 1237 + 892 + + + + + 900 + 500 + + + + Molecular Dynamics + + + + + 9 + + + + + + 0 + 23 + + + + + 16777215 + 23 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 285 + 0 + + + + + 285 + 16777215 + + + + + + 10 + 0 + 83 + 23 + + + + Step + + + + + + 100 + 0 + 83 + 23 + + + + Start + + + + + false + + + + 190 + 0 + 83 + 23 + + + + Stop + + + + + + + + Calculation time: 0 µs + + + Qt::AlignCenter + + + + + + + Frame time: 0 µs + + + Qt::AlignCenter + + + + + + + Refresh rate: 0.0 fps + + + Qt::AlignCenter + + + + + + + + 50 + 0 + + + + + 50 + 16777215 + + + + + + 10 + 0 + 30 + 23 + + + + ? + + + + + + + + + + + + 500 + 0 + + + + + + + + 0 + 0 + + + + + 280 + 0 + + + + + 280 + 16777215 + + + + QFrame::NoFrame + + + true + + + + + 0 + -2 + 266 + 617 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 6 + + + + + + 0 + 375 + + + + + 16777215 + 375 + + + + Display options + + + + + 20 + 25 + 227 + 71 + + + + Frameskip + + + Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft + + + + + 40 + 30 + 148 + 32 + + + + Qt::LeftToRight + + + false + + + true + + + Qt::AlignCenter + + + QAbstractSpinBox::NoButtons + + + false + + + false + + + 0 + + + 48 + + + + + + 11 + 31 + 30 + 30 + + + + Qt::NoFocus + + + + + + false + + + true + + + 200 + + + 75 + + + true + + + false + + + false + + + + + + 187 + 31 + 30 + 30 + + + + Qt::NoFocus + + + + + + false + + + true + + + 200 + + + 75 + + + true + + + false + + + false + + + + + + + 20 + 100 + 227 + 71 + + + + Force indicators + + + Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft + + + + + 10 + 25 + 181 + 21 + + + + Distance threshold + + + false + + + + + + 10 + 45 + 181 + 21 + + + + σ (Root of potential) + + + false + + + + + + 200 + 27 + 15 + 15 + + + + + + + + + 255 + 255 + 255 + + + + + + + 239 + 41 + 41 + + + + + + + + + 255 + 255 + 255 + + + + + + + 239 + 41 + 41 + + + + + + + + + 239 + 41 + 41 + + + + + + + 239 + 41 + 41 + + + + + + + + true + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + 0 + 0 + 15 + 15 + + + + + + + true + + + + + + + 200 + 50 + 15 + 15 + + + + + + + + + 255 + 255 + 255 + + + + + + + 0 + 0 + 255 + + + + + + + + + 255 + 255 + 255 + + + + + + + 0 + 0 + 255 + + + + + + + + + 0 + 0 + 255 + + + + + + + 0 + 0 + 255 + + + + + + + + true + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + 0 + 0 + 15 + 15 + + + + + + + true + + + + + + + + 20 + 175 + 227 + 71 + + + + Particle size + + + Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft + + + + + 40 + 30 + 148 + 32 + + + + Qt::LeftToRight + + + false + + + true + + + Qt::AlignCenter + + + QAbstractSpinBox::NoButtons + + + false + + + false + + + 1 + + + 48 + + + + + + 11 + 31 + 30 + 30 + + + + Qt::NoFocus + + + + + + false + + + true + + + 200 + + + 75 + + + true + + + false + + + false + + + + + + 187 + 31 + 30 + 30 + + + + Qt::NoFocus + + + + + + false + + + true + + + 200 + + + 75 + + + true + + + false + + + false + + + + + + + 20 + 251 + 227 + 71 + + + + Statistics update interval + + + Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft + + + + + 11 + 31 + 30 + 30 + + + + Qt::NoFocus + + + + + + false + + + true + + + 200 + + + 75 + + + true + + + false + + + false + + + + + + 187 + 31 + 30 + 30 + + + + Qt::NoFocus + + + + + + false + + + true + + + 200 + + + 75 + + + true + + + false + + + false + + + + + + 40 + 30 + 148 + 32 + + + + Qt::AlignCenter + + + QAbstractSpinBox::NoButtons + + + 4 + + + 0.000000000000000 + + + 100.000000000000000 + + + 0.000100000000000 + + + 1.000000000000000 + + + + + + + 70 + 330 + 141 + 31 + + + + Apply + + + + + + + + + 0 + 220 + + + + + 16777215 + 220 + + + + Heat bath + + + + + 40 + 180 + 91 + 31 + + + + Apply + + + + + + 20 + 25 + 227 + 71 + + + + Target temperature + + + Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft + + + + + 11 + 31 + 30 + 30 + + + + Qt::NoFocus + + + + + + false + + + true + + + 200 + + + 75 + + + true + + + false + + + false + + + + + + 187 + 31 + 30 + 30 + + + + Qt::NoFocus + + + + + + false + + + true + + + 200 + + + 75 + + + true + + + false + + + false + + + + + + 40 + 30 + 148 + 32 + + + + Qt::AlignCenter + + + QAbstractSpinBox::NoButtons + + + 4 + + + 0.000000000000000 + + + 100.000000000000000 + + + 0.000100000000000 + + + 1.000000000000000 + + + + + + + 20 + 100 + 227 + 71 + + + + Transition time x100 frames + + + Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft + + + + + 11 + 31 + 30 + 30 + + + + Qt::NoFocus + + + + + + false + + + true + + + 200 + + + 75 + + + true + + + false + + + false + + + + + + 187 + 31 + 30 + 30 + + + + Qt::NoFocus + + + + + + false + + + true + + + 200 + + + 75 + + + true + + + false + + + false + + + + + + 40 + 30 + 148 + 32 + + + + Qt::AlignCenter + + + QAbstractSpinBox::NoButtons + + + 1 + + + 100 + + + 10 + + + + + + false + + + + 140 + 180 + 91 + 31 + + + + Abort + + + + + + + + + 0 + 0 + + + + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + + + + + + 0 + 0 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + + + + + + 0 + 0 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + + + 0 + 0 + + + + + + + + + + + + 0 + 0 + + + + + + + + + + + + 280 + 0 + + + + + 280 + 16777215 + + + + QFrame::NoFrame + + + Qt::ScrollBarAlwaysOff + + + true + + + + + 0 + 0 + 266 + 670 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 660 + + + + + 16777215 + 660 + + + + Simulation paramters + + + + + 20 + 325 + 227 + 71 + + + + Maximum initial deviation + + + Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft + + + + + 11 + 31 + 30 + 30 + + + + Qt::NoFocus + + + + + + false + + + true + + + 200 + + + 75 + + + true + + + false + + + false + + + + + + 187 + 31 + 30 + 30 + + + + Qt::NoFocus + + + + + + false + + + true + + + 200 + + + 75 + + + true + + + false + + + false + + + + + + 40 + 30 + 148 + 32 + + + + Qt::AlignCenter + + + QAbstractSpinBox::NoButtons + + + 4 + + + 0.000000000000000 + + + 100.000000000000000 + + + 0.000100000000000 + + + 1.000000000000000 + + + + + + + 70 + 620 + 141 + 31 + + + + Reinitialize + + + + + + 20 + 100 + 227 + 71 + + + + Number of particles + + + Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft + + + + + 69 + 30 + 90 + 32 + + + + Qt::LeftToRight + + + false + + + true + + + Qt::AlignCenter + + + QAbstractSpinBox::NoButtons + + + false + + + false + + + 1 + + + 1048576 + + + 1 + + + + + + 11 + 31 + 30 + 30 + + + + Qt::NoFocus + + + ◀◀ + + + false + + + true + + + 200 + + + 75 + + + true + + + false + + + false + + + + + + 158 + 31 + 30 + 30 + + + + Qt::NoFocus + + + + + + false + + + true + + + 200 + + + 75 + + + true + + + false + + + false + + + + + + 40 + 31 + 30 + 30 + + + + Qt::NoFocus + + + + + + false + + + true + + + 200 + + + 75 + + + true + + + false + + + false + + + + + + 187 + 31 + 30 + 30 + + + + Qt::NoFocus + + + ▶▶ + + + false + + + true + + + 200 + + + 75 + + + true + + + false + + + false + + + + + + + 20 + 250 + 227 + 71 + + + + Timestep + + + Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft + + + + + 11 + 31 + 30 + 30 + + + + Qt::NoFocus + + + + + + false + + + true + + + 200 + + + 75 + + + true + + + false + + + false + + + + + + 187 + 31 + 30 + 30 + + + + Qt::NoFocus + + + + + + false + + + true + + + 200 + + + 75 + + + true + + + false + + + false + + + + + + 40 + 30 + 148 + 32 + + + + Qt::AlignCenter + + + QAbstractSpinBox::NoButtons + + + 4 + + + 0.000100000000000 + + + 100.000000000000000 + + + 0.000100000000000 + + + 1.000000000000000 + + + + + + + 20 + 400 + 227 + 71 + + + + Maximum initial velocity + + + Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft + + + + + 11 + 31 + 30 + 30 + + + + Qt::NoFocus + + + + + + false + + + true + + + 200 + + + 75 + + + true + + + false + + + false + + + + + + 187 + 31 + 30 + 30 + + + + Qt::NoFocus + + + + + + false + + + true + + + 200 + + + 75 + + + true + + + false + + + false + + + + + + 40 + 30 + 148 + 32 + + + + Qt::AlignCenter + + + QAbstractSpinBox::NoButtons + + + 4 + + + 0.000000000000000 + + + 100.000000000000000 + + + 0.000100000000000 + + + 1.000000000000000 + + + + + + + 20 + 25 + 227 + 71 + + + + Number of threads + + + Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft + + + + + 40 + 30 + 148 + 32 + + + + Qt::LeftToRight + + + false + + + true + + + Qt::AlignCenter + + + QAbstractSpinBox::NoButtons + + + false + + + false + + + + + + 1 + + + 48 + + + + + + 11 + 31 + 30 + 30 + + + + Qt::NoFocus + + + + + + false + + + true + + + 200 + + + 75 + + + true + + + false + + + false + + + + + + 187 + 31 + 30 + 30 + + + + Qt::NoFocus + + + + + + false + + + true + + + 200 + + + 75 + + + true + + + false + + + false + + + + + + + 20 + 475 + 227 + 52 + + + + Periodic boundary condition + + + Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft + + + + + 10 + 25 + 201 + 21 + + + + Enabled + + + false + + + + + + + 20 + 175 + 227 + 71 + + + + Length of the lattice + + + Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft + + + + + 11 + 31 + 30 + 30 + + + + Qt::NoFocus + + + + + + false + + + true + + + 200 + + + 75 + + + true + + + false + + + false + + + + + + 187 + 31 + 30 + 30 + + + + Qt::NoFocus + + + + + + false + + + true + + + 200 + + + 75 + + + true + + + false + + + false + + + + + + 40 + 30 + 148 + 32 + + + + Qt::AlignCenter + + + QAbstractSpinBox::NoButtons + + + 1.000000000000000 + + + 100.000000000000000 + + + + + + + 20 + 535 + 227 + 71 + + + + Distance threshold for forces + + + Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft + + + + + 11 + 31 + 30 + 30 + + + + Qt::NoFocus + + + + + + false + + + true + + + 200 + + + 75 + + + true + + + false + + + false + + + + + + 187 + 31 + 30 + 30 + + + + Qt::NoFocus + + + + + + false + + + true + + + 200 + + + 75 + + + true + + + false + + + false + + + + + + 40 + 30 + 148 + 32 + + + + Qt::AlignCenter + + + QAbstractSpinBox::NoButtons + + + 0.000000000000000 + + + 100.000000000000000 + + + + + + + + + + 0 + 0 + + + + + + + + + + cont_lvl2_1 + scrl_area_right + scrl_area_left + + + + + + + 0 + 100 + + + + + 16777215 + 100 + + + + QFrame::StyledPanel + + + + + + + + 0 + 100 + + + + + 16777215 + 100 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + + + + + diff --git a/md-gui/src/md-gui.pro b/md-gui/src/md-gui.pro new file mode 100644 index 0000000..e3ce7d8 --- /dev/null +++ b/md-gui/src/md-gui.pro @@ -0,0 +1,33 @@ +#------------------------------------------------- +# +# Project created by QtCreator 2017-01-19T08:04:57 +# +#------------------------------------------------- + +QT += core gui + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +TARGET = md-gui +TEMPLATE = app + +# The following define makes your compiler emit warnings if you use +# any feature of Qt which as been marked as deprecated (the exact warnings +# depend on your compiler). Please consult the documentation of the +# deprecated API in order to know how to port your code away from it. +DEFINES += QT_DEPRECATED_WARNINGS + +# You can also make your code fail to compile if you use deprecated APIs. +# In order to do so, uncomment the following line. +# You can also select to disable deprecated APIs only up to a certain version of Qt. +#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 + + +SOURCES += main.cpp\ + mainwindow.cpp \ +../../md-core/md-core.c + +HEADERS += mainwindow.h \ +../../md-core/md-core.h + +FORMS += mainwindow.ui