diff --git a/vector/Makefile b/vector/Makefile index 7244ac59af5..2223e5ade5f 100644 --- a/vector/Makefile +++ b/vector/Makefile @@ -40,6 +40,7 @@ SUBDIRS = \ v.lidar.growing \ v.lrs \ v.proj \ + v.ppa \ v.mkgrid \ v.neighbors \ v.net \ diff --git a/vector/v.ppa/Makefile b/vector/v.ppa/Makefile new file mode 100644 index 00000000000..32b1b0bbd84 --- /dev/null +++ b/vector/v.ppa/Makefile @@ -0,0 +1,14 @@ + +MODULE_TOPDIR = ../.. + +PGM=v.ppa + +LIBES = $(VECTORLIB) $(DBMILIB) $(BTREE2LIB) $(GISLIB) $(PARSONLIB) +EXTRA_LIBS = $(OPENMP_LIBPATH) $(OPENMP_LIB) +DEPENDENCIES = $(VECTORDEP) $(DBMIDEP) $(BTREE2DEP) $(GISDEP) +EXTRA_INC = $(VECT_INC) $(OPENMP_INCPATH) +EXTRA_CFLAGS = $(VECT_CFLAGS) $(OPENMP_CFLAGS) + +include $(MODULE_TOPDIR)/include/Make/Module.make + +default: cmd diff --git a/vector/v.ppa/local_proto.h b/vector/v.ppa/local_proto.h new file mode 100644 index 00000000000..e69de29bb2d diff --git a/vector/v.ppa/main.c b/vector/v.ppa/main.c new file mode 100644 index 00000000000..0b71cf12397 --- /dev/null +++ b/vector/v.ppa/main.c @@ -0,0 +1,767 @@ +#if defined(_OPENMP) +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct Point { + double x, y; + int id; +}; + +enum OutputFormat { PLAIN, JSON }; + +void calculate_g_function(struct kdtree *kdtree, struct Point *points, int n, + int i, const char *output_file); +void calculate_g_function_values(struct kdtree *kdtree, struct Point *points, + int n, int num_distances, double *values); +void calculate_f_function(struct kdtree *kdtree, struct Point *points, int n, + const char *output_file, struct bound_box *box, + int num_random_points); +void calculate_f_function_values(struct kdtree *kdtree, struct Point *points, + int n, struct bound_box *box, double *values, + int num_random_points); + +void calculate_k_function(struct kdtree *kdtree, struct Point *points, int n, + int num_distances, double intensity, + const char *output_file, enum OutputFormat format, + JSON_Object *root_object); +void calculate_l_function(struct kdtree *kdtree, struct Point *points, int n, + int num_distances, double intensity, + const char *output_file, enum OutputFormat format, + JSON_Object *root_object); +void calculate_k_function_values(struct kdtree *kdtree, struct Point *points, + int n, int num_distances, double max_dist, + double intensity, double *values); +void calculate_l_function_values(struct kdtree *kdtree, struct Point *points, + int n, int num_distances, double max_dist, + double intensity, double *values); +double max_distance(struct Point *points, int n); +double euclidean_distance(const struct Point *p1, const struct Point *p2); +void generate_random_points(struct Point *random_points, int num_random_points, + struct bound_box *box); +double csr_g_value(double d, double i); +void calculate_function_values( + struct kdtree *kdtree, struct Point *points, int n, double *values, + int num_distances, double max_dist, + void (*calc_func)(struct kdtree *, struct Point *, int, double *)); +void monte_carlo_envelope(struct kdtree *kdtree, struct Point *points, + struct bound_box *box, int n, const char *output_file, + int num_simulations, + void (*calc_func)(struct kdtree *, struct Point *, + int, double *)); +int main(int argc, char *argv[]) +{ + struct Map_info Map; + + // Initialize the GIS environment + G_gisinit(argv[0]); + + // Set up module description + struct GModule *module = G_define_module(); + G_add_keyword(_("vector")); + G_add_keyword(_("point pattern analysis")); + G_add_keyword(_("parallel")); + G_add_keyword(_("statistics")); + module->description = + _("Point pattern analysis using G, F, K, and L functions."); + + // Define options + struct Option *input_opt = G_define_standard_option(G_OPT_V_INPUT); + struct Option *output_opt = G_define_standard_option(G_OPT_F_OUTPUT); + output_opt->required = NO; + + struct Option *method_opt = G_define_option(); + method_opt->key = "method"; + method_opt->type = TYPE_STRING; + method_opt->required = YES; + method_opt->options = "g,f,k,l"; + method_opt->description = _("Method to calculate (g, f, k, l)"); + + struct Option *random_points_opt = G_define_option(); + random_points_opt->key = "random_points"; + random_points_opt->type = TYPE_INTEGER; + random_points_opt->required = NO; + random_points_opt->answer = "1000"; + random_points_opt->description = + _("Number of random points for F-function calculation (default: 1000)"); + + struct Option *format_opt = G_define_standard_option(G_OPT_F_FORMAT); + format_opt->required = NO; + + struct Option *num_distances_opt = G_define_option(); + num_distances_opt->key = "num_distances"; + num_distances_opt->type = TYPE_INTEGER; + num_distances_opt->required = NO; + num_distances_opt->answer = "100"; + num_distances_opt->description = _("Number of distances (default: 100)"); + + struct Option *simulations_opt = G_define_option(); + simulations_opt->key = "simulations"; + simulations_opt->type = TYPE_INTEGER; + simulations_opt->required = NO; + simulations_opt->answer = "99"; + simulations_opt->description = + _("Number of simulations for Monte Carlo envelope (default: 99)"); + + struct Option *random_seed = G_define_option(); + random_seed->key = "seed"; + random_seed->type = TYPE_INTEGER; + random_seed->required = NO; + random_seed->label = _("Seed for random number generator"); + random_seed->description = + _("The same seed can be used to obtain same results" + " or random seed can be generated by other means."); + + if (G_parser(argc, argv)) + exit(EXIT_FAILURE); + + /****** INITIALISE RANDOM NUMBER GENERATOR ******/ + long seed_value; + if (random_seed->answer) { + seed_value = atol(random_seed->answer); + G_srand48(seed_value); + G_verbose_message(_("Read random seed from %s option: %ld"), + random_seed->key, seed_value); + } + else { + /* default as it used to be */ + seed_value = G_srand48_auto(); + G_verbose_message(_("Autogenerated random seed set to: %ld"), + seed_value); + } + + const char *input_vector = input_opt->answer; + const char *output_file = output_opt->answer; + const char *method = method_opt->answer; + + int num_random_points = atoi(random_points_opt->answer); + int num_distances = atoi(num_distances_opt->answer); + int num_simulations = atoi(simulations_opt->answer); + + // Open the vector map + if (Vect_open_old(&Map, input_vector, "") < 0) + G_fatal_error(_("Unable to open vector map <%s>"), input_vector); + + enum OutputFormat format; + JSON_Value *root_value; + JSON_Object *root_object; + + if (strcmp(format_opt->answer, "json") == 0) { + format = JSON; + root_value = json_value_init_object(); + if (root_value == NULL) { + G_fatal_error(_("Unable to initialize JSON object")); + } + root_object = json_object(root_value); + } + else { + format = PLAIN; + } + + // Allocate memory for points + struct line_pnts *points = Vect_new_line_struct(); + struct line_cats *cats = Vect_new_cats_struct(); + int nlines = Vect_get_num_lines(&Map); + + int n = Vect_get_num_primitives(&Map, GV_POINT); + + // Allocate memory for points array + struct Point *pts = (struct Point *)malloc(n * sizeof(struct Point)); + int idx = 0; + + // Store points + // Initialize k-d tree + struct kdtree *kdtree = kdtree_create(2, NULL); + + for (int line = 1; line <= nlines; line++) { + if (Vect_read_line(&Map, points, cats, line) == GV_POINT) { + pts[idx].x = points->x[0]; + pts[idx].y = points->y[0]; + pts[idx].id = idx; + double coords[2] = {points->x[0], points->y[0]}; + kdtree_insert(kdtree, coords, idx, 0); + idx++; + } + } + + // Get bounding box + struct bound_box box; + Vect_get_map_box(&Map, &box); + // Calculate mean number of points per unit area (intensity) + double area = (box.E - box.W) * (box.N - box.S); + double intensity = (double)n / area; + G_message(_("intensity: %f"), intensity); + + G_message(_("Number of points: %d"), n); + G_message(_("Method: %s"), method); + + if (strcmp(method, "k") == 0) { + calculate_k_function(kdtree, pts, n, num_distances, intensity, + output_file, format, root_object); + } + else if (strcmp(method, "l") == 0) { + calculate_l_function(kdtree, pts, n, num_distances, intensity, + output_file, format, root_object); + } + else if (strcmp(method, "f") == 0) { + calculate_f_function(kdtree, pts, n, output_file, &box, + num_random_points); + } + else if (strcmp(method, "g") == 0) { + calculate_g_function(kdtree, pts, n, intensity, output_file); + } + else { + G_fatal_error(_("Method not implemented yet")); + } + + // Free memory and close the vector map + free(pts); + kdtree_destroy(kdtree); // Ensure k-d tree is destroyed + Vect_close(&Map); + + if (format == JSON) { + char *serialized_string = NULL; + serialized_string = json_serialize_to_string_pretty(root_value); + if (serialized_string == NULL) { + G_fatal_error(_("Failed to initialize pretty JSON string.")); + } + puts(serialized_string); + if (output_file) { + FILE *fp = fopen(output_file, "w"); + if (fp == NULL) { + G_fatal_error(_("Unable to open output file <%s>"), + output_file); + } + fputs(serialized_string, fp); + fclose(fp); + } + json_free_serialized_string(serialized_string); + json_value_free(root_value); + } + + return 0; +} + +double max_distance(struct Point *points, int n) +{ + double max_dist = 0.0; +#pragma omp parallel for reduction(max : max_dist) + for (int i = 0; i < n; i++) { + for (int j = 0; j < n; j++) { + if (i != j) { + double dist = euclidean_distance(&points[i], &points[j]); + if (dist > max_dist) { + max_dist = dist; + } + } + } + } + max_dist = sqrt(max_dist); + return max_dist; +} + +void calculate_function_values(struct kdtree *kdtree, struct Point *points, + int n, double *values, int num_distances, + double max_dist, + void (*calc_func)(struct kdtree *, + struct Point *, int, double *)) +{ + calc_func(kdtree, points, n, values); +} + +/** + * Calculates the F function for a given set of points and generates an envelope + * using Monte Carlo simulations. + * + * @param kdtree The k-d tree used for nearest neighbor searches. + * @param points An array of Point structures representing the points. + * @param box The bounding box of the map. + * @param n The number of points in the array. + * @param output_file The path to the output file where the results will be + * saved. + * @param num_random_points The number of random points to generate for F + * function calculation. + * @param num_simulations The number of Monte Carlo simulations to perform. + */ +void monte_carlo_envelope(struct kdtree *kdtree, struct Point *points, + struct bound_box *box, int n, const char *output_file, + int num_simulations, + void (*calc_func)(struct kdtree *, struct Point *, + int, double *)) +{ + FILE *fp = fopen(output_file, "w"); + if (fp == NULL) { + G_fatal_error(_("Unable to open output file <%s>"), output_file); + } + + struct Point *random_points = + (struct Point *)malloc(n * sizeof(struct Point)); + + double max_dist = max_distance(points, n); + + int num_distances = 100; + double *values = (double *)malloc(num_distances * sizeof(double)); + double *lower_envelope = (double *)malloc(num_distances * sizeof(double)); + double *upper_envelope = (double *)malloc(num_distances * sizeof(double)); + + for (int d = 0; d < num_distances; d++) { + lower_envelope[d] = DBL_MAX; + upper_envelope[d] = DBL_MIN; + } + +#pragma omp parallel for + for (int sim = 0; sim < num_simulations; sim++) { + generate_random_points( + random_points, n, + box); // Generate same number of random points as observed points + double *sim_values = (double *)malloc(num_distances * sizeof(double)); + calculate_function_values(kdtree, random_points, n, sim_values, + num_distances, max_dist, calc_func); + +#pragma omp critical + { + for (int d = 0; d < num_distances; d++) { + if (sim_values[d] < lower_envelope[d]) { + lower_envelope[d] = sim_values[d]; + } + if (sim_values[d] > upper_envelope[d]) { + upper_envelope[d] = sim_values[d]; + } + } + } + free(sim_values); + } + + fprintf(fp, "Distance,Lower Envelope,Upper Envelope\n"); + for (int d = 0; d < num_distances; d++) { + double distance = d * max_dist / num_distances; + fprintf(fp, "%f,%f,%f\n", distance, lower_envelope[d], + upper_envelope[d]); + } + + free(random_points); + free(values); + free(lower_envelope); + free(upper_envelope); + fclose(fp); +} + +double euclidean_distance(const struct Point *p1, const struct Point *p2) +{ + return (p1->x - p2->x) * (p1->x - p2->x) + + (p1->y - p2->y) * (p1->y - p2->y); +} + +void generate_random_points(struct Point *random_points, int num_random_points, + struct bound_box *box) +{ + for (int i = 0; i < num_random_points; i++) { + random_points[i].x = box->W + (box->E - box->W) * (double)G_drand48(); + random_points[i].y = box->S + (box->N - box->S) * (double)G_drand48(); + random_points[i].id = i; + } +} + +/** + * Calculates the g function for a given array of points. + * G(d) = 1 - exp(-i * π * d^2) + * + * @param d The distance. + * @param i The intensity (points per unit area). + * @return The g value. + */ +double csr_g_value(double d, double i) +{ + return 1 - exp(-i * M_PI * d * d); +} + +/** + * Calculates the L function for a given array of points. + * L(d) = √(K(d) / π) + * + * @param points The array of points. + * @param n The number of points in the array. + * @param output_file The path to the output file where the results will be + * written. + */ +void calculate_l_function(struct kdtree *kdtree, struct Point *points, int n, + int num_distances, double intensity, + const char *output_file, enum OutputFormat format, + JSON_Object *root_object) +{ + FILE *fp = NULL; + double max_dist = max_distance(points, n); + double interval = max_dist / num_distances; + double *values = (double *)malloc(num_distances * sizeof(double)); + if (values == NULL) { + G_fatal_error(_("Unable to allocate memory for values array.")); + } + calculate_l_function_values(kdtree, points, n, num_distances, max_dist, + intensity, values); + + switch (format) { + case PLAIN: + fp = fopen(output_file, "w"); + if (fp == NULL) { + G_fatal_error(_("Unable to open output file <%s>"), output_file); + } + + fprintf(fp, "Distance,L-value\n"); + for (int d = 0; d < num_distances; d++) { + fprintf(fp, "%f,%f\n", d * interval, values[d]); + } + fclose(fp); + break; + case JSON: + if (root_object == NULL) { + G_fatal_error(_("root_object is NULL.")); + } + json_object_set_null(root_object, "distance"); + json_object_set_null(root_object, "l-value"); + JSON_Value *distance = json_value_init_array(); + if (distance == NULL) { + G_fatal_error(_("Unable to initialize JSON distance array.")); + } + JSON_Array *distances = json_array(distance); + + JSON_Value *l_value = json_value_init_array(); + if (l_value == NULL) { + G_fatal_error(_("Unable to initialize JSON l-value array.")); + } + JSON_Array *l_values = json_array(l_value); + for (int d = 0; d < num_distances; d++) { + json_array_append_number(distances, d * interval); + json_array_append_number(l_values, values[d]); + } + json_object_set_value(root_object, "distance", distance); + json_object_set_value(root_object, "l-value", l_value); + break; + } + free(values); +} + +/** + * Calculates the f function for a given array of points. + * + * @param kdtree The k-d tree used for nearest neighbor search. + * @param points The array of points. + * @param n The number of points in the array. + * @param output_file The output file to write the results to. + * @param num_random_points The number of random points to generate. + */ +void calculate_f_function(struct kdtree *kdtree, struct Point *points, int n, + const char *output_file, struct bound_box *box, + int num_random_points) +{ + FILE *fp = fopen(output_file, "w"); + if (fp == NULL) { + G_fatal_error(_("Unable to open output file <%s>"), output_file); + } + + // Generate random points + struct Point *random_points = + (struct Point *)malloc(num_random_points * sizeof(struct Point)); + + generate_random_points(random_points, num_random_points, box); + + double max_dist = 0.0; + double *distances = (double *)malloc(num_random_points * sizeof(double)); + +#pragma omp parallel for reduction(max : max_dist) + for (int i = 0; i < num_random_points; i++) { + double coords[2] = {random_points[i].x, random_points[i].y}; + int puid; + double pd; + kdtree_knn(kdtree, coords, &puid, &pd, 1, NULL); + distances[i] = sqrt(pd); + if (distances[i] > max_dist) { + max_dist = distances[i]; + } + } + + G_message(_("Max distance: %f"), max_dist); + + fprintf(fp, "Distance,F-value\n"); + for (double d = 0.0; d <= max_dist; d += max_dist / 100.0) { + double f_value = 0.0; + +#pragma omp parallel for reduction(+ : f_value) + for (int i = 0; i < num_random_points; i++) { + if (distances[i] <= d) { + f_value += 1; + } + } + + f_value /= num_random_points; + fprintf(fp, "%f,%f\n", d, f_value); + } + + free(random_points); + free(distances); + fclose(fp); +} + +/** + * Calculates the G-Function for a given set of points and writes the results to + * an output file. + * + * @param kdtree The k-d tree data structure used for nearest neighbor search. + * @param points An array of Point structures representing the input points. + * @param n The number of points in the input array. + * @param i The intensity of the point being processed. + * @param output_file The path to the output file where the results will be + * written. + */ +void calculate_g_function(struct kdtree *kdtree, struct Point *points, int n, + int i, const char *output_file) +{ + G_message(_("G-Function")); + FILE *fp = fopen(output_file, "w"); + if (fp == NULL) { + G_fatal_error(_("Unable to open output file <%s>"), output_file); + } + + double max_dist = 0.0; + double *nearest_distances = (double *)malloc(n * sizeof(double)); + +#pragma omp parallel for reduction(max : max_dist) + for (int i = 0; i < n; i++) { + double coords[2] = {points[i].x, points[i].y}; + int puid = 0; + double pd = 0.0; + kdtree_knn( + kdtree, coords, &puid, &pd, 2, + &points[i] + .id); // Find the nearest neighbor excluding the point itself + + nearest_distances[i] = sqrt(pd); + if (nearest_distances[i] > max_dist) { + max_dist = nearest_distances[i]; + } + } + G_message(_("Max distance: %f"), max_dist); + double g_value_csr = 0.0; + fprintf(fp, "Distance,G-value,G-value-CSR\n"); + for (double d = 0.0; d <= max_dist; d += max_dist / 100) { + double g_value = 0.0; + +#pragma omp parallel for reduction(+ : g_value) + for (int i = 0; i < n; i++) { + if (nearest_distances[i] <= d) { + g_value += 1.0; + } + } + g_value_csr = csr_g_value(d, i); + g_value /= n; // Normalize g-value + fprintf(fp, "%f,%f,%f\n", d, g_value, g_value_csr); + } + + free(nearest_distances); + fclose(fp); +} + +void calculate_k_function(struct kdtree *kdtree, struct Point *points, int n, + int num_distances, double intensity, + const char *output_file, enum OutputFormat format, + JSON_Object *root_object) +{ + double max_dist = max_distance(points, n); + double interval = max_dist / num_distances; + G_message(_("Max distance: %f"), max_dist); + double *values = (double *)malloc(num_distances * sizeof(double)); + calculate_k_function_values(kdtree, points, n, num_distances, max_dist, + intensity, values); + + switch (format) { + case PLAIN: + FILE *fp = fopen(output_file, "w"); + if (fp == NULL) { + G_fatal_error(_("Unable to open output file <%s>"), output_file); + } + + fprintf(fp, "Distance,K-value\n"); + for (int d = 0; d < num_distances; d++) { + fprintf(fp, "%f,%f\n", d * interval, values[d]); + } + fclose(fp); + break; + case JSON: + JSON_Value *distance = json_value_init_array(); + if (distance == NULL) { + G_fatal_error(_("Unable to initialize JSON distance array.")); + } + JSON_Array *distances = json_array(distance); + + JSON_Value *k_value = json_value_init_array(); + if (k_value == NULL) { + G_fatal_error(_("Unable to initialize JSON k-value array.")); + } + JSON_Array *k_values = json_array(k_value); + + for (int d = 0; d < num_distances; d++) { + json_array_append_number(distances, d * interval); + json_array_append_number(k_values, values[d]); + } + json_object_set_value(root_object, "distance", distance); + json_object_set_value(root_object, "k-value", k_value); + break; + } + free(values); +} + +void calculate_g_function_values(struct kdtree *kdtree, struct Point *points, + int n, int num_distances, double *values) +{ + double max_dist = 0.0; + double *nearest_distances = (double *)malloc(n * sizeof(double)); + +// Calculate the nearest neighbor distances for each point and find the maximum +// distance +#pragma omp parallel for reduction(max : max_dist) + for (int i = 0; i < n; i++) { + double coords[2] = {points[i].x, points[i].y}; + int puid = 0; + double pd = 0.0; + kdtree_knn( + kdtree, coords, &puid, &pd, 2, + &points[i] + .id); // Find the nearest neighbor excluding the point itself + + nearest_distances[i] = sqrt(pd); + if (nearest_distances[i] > max_dist) { + max_dist = nearest_distances[i]; + } + } + + double interval = max_dist / num_distances; + + // Initialize the G-values array + for (int d = 0; d < num_distances; d++) { + values[d] = 0.0; + } + + // Calculate G-values for the specified distances + for (int d = 0; d < num_distances; d++) { + double dist = d * interval; + double g_value = 0.0; + +#pragma omp parallel for reduction(+ : g_value) + for (int i = 0; i < n; i++) { + if (nearest_distances[i] <= dist) { + g_value += 1.0; + } + } + values[d] = g_value / n; + } + + free(nearest_distances); +} + +// You need to implement these placeholder functions +void calculate_k_function_values(struct kdtree *kdtree, struct Point *points, + int n, int num_distances, double max_dist, + double intensity, double *values) +{ + + double interval = max_dist / num_distances; + + G_percent(0, num_distances, 1); +#pragma omp parallel for + for (int d = 0; d < num_distances; d++) { + double k_value = 0.0; + double radius = d * interval; + +#pragma omp parallel for reduction(+ : k_value) + for (int i = 0; i < n; i++) { + double coords[2] = {points[i].x, points[i].y}; + int count; + int *puid = NULL; + double *pd = NULL; + count = + kdtree_dnn(kdtree, coords, &puid, &pd, radius, &points[i].id); + + if (count > 0) { + k_value += count - 1; // subtract 1 to exclude the point itself + } + + free(puid); + free(pd); + } + + k_value /= (n * intensity); + values[d] = k_value; + + // Update progress indicator + G_percent(d, num_distances, 1); + } + + // Finalize the progress indicator + G_percent(num_distances, num_distances, 1); +} + +void calculate_l_function_values(struct kdtree *kdtree, struct Point *points, + int n, int num_distances, double max_dist, + double intensity, double *values) +{ + + calculate_k_function_values(kdtree, points, n, num_distances, max_dist, + intensity, values); +#pragma omp parallel for + for (int i = 0; i < num_distances; i++) { + values[i] = sqrt(values[i] / M_PI); + } +} + +void calculate_f_function_values(struct kdtree *kdtree, struct Point *points, + int n, struct bound_box *box, double *values, + int num_random_points) +{ + + // Generate random points + struct Point *random_points = + (struct Point *)malloc(num_random_points * sizeof(struct Point)); + + generate_random_points(random_points, num_random_points, box); + + double max_dist = 0.0; + double *distances = (double *)malloc(num_random_points * sizeof(double)); + +#pragma omp parallel for reduction(max : max_dist) + for (int i = 0; i < num_random_points; i++) { + double coords[2] = {random_points[i].x, random_points[i].y}; + int puid; + double pd; + kdtree_knn(kdtree, coords, &puid, &pd, 1, NULL); + distances[i] = sqrt(pd); + if (distances[i] > max_dist) { + max_dist = distances[i]; + } + } + + for (int d = 0.0; d <= max_dist; d += max_dist / 100.0) { + double f_value = 0.0; + +#pragma omp parallel for reduction(+ : f_value) + for (int i = 0; i < num_random_points; i++) { + if (distances[i] <= d) { + f_value += 1; + } + } + + f_value /= num_random_points; + values[d] = f_value; + } + + free(random_points); + free(distances); +} diff --git a/vector/v.ppa/testsuite/README.md b/vector/v.ppa/testsuite/README.md new file mode 100644 index 00000000000..42d0dd264cb --- /dev/null +++ b/vector/v.ppa/testsuite/README.md @@ -0,0 +1,12 @@ +# Test Data + +Test data was downloaded from the City of Raleigh, NC open data portal. +The data is a subset of the Daily Police Incidents dataset filtered from 2022 - 2024. + +[Daily_Police_Incidents](https://services.arcgis.com/v400IkDOw1ad7Yad/arcgis/rest/services/Daily_Police_Incidents/FeatureServer/0/query?where=1%3D1&outFields=*&outSR=3358&f=json) + +```bash +v.import input=https://services.arcgis.com/v400IkDOw1ad7Yad/arcgis/rest/ \ +services/Daily_Police_Incidents/FeatureServer/0/query?where=1%3D1 \ +&outFields=*&outSR=3358&f=json layer=ESRIJSON output=raleigh_crime_2022_2024 +``` diff --git a/vector/v.ppa/testsuite/data/raleigh_crime_2022_2024.fgb b/vector/v.ppa/testsuite/data/raleigh_crime_2022_2024.fgb new file mode 100644 index 00000000000..5d0fceb31c9 Binary files /dev/null and b/vector/v.ppa/testsuite/data/raleigh_crime_2022_2024.fgb differ diff --git a/vector/v.ppa/testsuite/outputs/f_crime.csv b/vector/v.ppa/testsuite/outputs/f_crime.csv new file mode 100644 index 00000000000..31f04196550 --- /dev/null +++ b/vector/v.ppa/testsuite/outputs/f_crime.csv @@ -0,0 +1,102 @@ +Distance,F-value +0.000000,0.000000 +76.844909,0.000000 +153.689817,0.009000 +230.534726,0.021000 +307.379635,0.042000 +384.224543,0.064000 +461.069452,0.090000 +537.914361,0.141000 +614.759269,0.163000 +691.604178,0.192000 +768.449087,0.219000 +845.293995,0.259000 +922.138904,0.288000 +998.983812,0.313000 +1075.828721,0.342000 +1152.673630,0.379000 +1229.518538,0.410000 +1306.363447,0.441000 +1383.208356,0.460000 +1460.053264,0.494000 +1536.898173,0.521000 +1613.743082,0.537000 +1690.587990,0.553000 +1767.432899,0.575000 +1844.277808,0.594000 +1921.122716,0.611000 +1997.967625,0.629000 +2074.812534,0.644000 +2151.657442,0.653000 +2228.502351,0.670000 +2305.347260,0.686000 +2382.192168,0.693000 +2459.037077,0.712000 +2535.881986,0.722000 +2612.726894,0.738000 +2689.571803,0.749000 +2766.416712,0.763000 +2843.261620,0.770000 +2920.106529,0.782000 +2996.951437,0.791000 +3073.796346,0.800000 +3150.641255,0.809000 +3227.486163,0.814000 +3304.331072,0.826000 +3381.175981,0.838000 +3458.020889,0.845000 +3534.865798,0.850000 +3611.710707,0.859000 +3688.555615,0.868000 +3765.400524,0.871000 +3842.245433,0.878000 +3919.090341,0.883000 +3995.935250,0.886000 +4072.780159,0.896000 +4149.625067,0.897000 +4226.469976,0.903000 +4303.314885,0.908000 +4380.159793,0.914000 +4457.004702,0.917000 +4533.849611,0.922000 +4610.694519,0.927000 +4687.539428,0.928000 +4764.384337,0.930000 +4841.229245,0.931000 +4918.074154,0.935000 +4994.919062,0.937000 +5071.763971,0.941000 +5148.608880,0.944000 +5225.453788,0.946000 +5302.298697,0.950000 +5379.143606,0.952000 +5455.988514,0.953000 +5532.833423,0.956000 +5609.678332,0.957000 +5686.523240,0.960000 +5763.368149,0.963000 +5840.213058,0.963000 +5917.057966,0.964000 +5993.902875,0.967000 +6070.747784,0.968000 +6147.592692,0.972000 +6224.437601,0.977000 +6301.282510,0.980000 +6378.127418,0.983000 +6454.972327,0.987000 +6531.817236,0.991000 +6608.662144,0.993000 +6685.507053,0.993000 +6762.351962,0.993000 +6839.196870,0.994000 +6916.041779,0.994000 +6992.886687,0.995000 +7069.731596,0.995000 +7146.576505,0.995000 +7223.421413,0.996000 +7300.266322,0.997000 +7377.111231,0.997000 +7453.956139,0.999000 +7530.801048,0.999000 +7607.645957,0.999000 +7684.490865,0.999000 diff --git a/vector/v.ppa/testsuite/outputs/f_crime.json b/vector/v.ppa/testsuite/outputs/f_crime.json new file mode 100644 index 00000000000..0967ef424bc --- /dev/null +++ b/vector/v.ppa/testsuite/outputs/f_crime.json @@ -0,0 +1 @@ +{} diff --git a/vector/v.ppa/testsuite/outputs/g_crime.csv b/vector/v.ppa/testsuite/outputs/g_crime.csv new file mode 100644 index 00000000000..ea2a7986b09 --- /dev/null +++ b/vector/v.ppa/testsuite/outputs/g_crime.csv @@ -0,0 +1,101 @@ +Distance,G-value,G-value-CSR +0.000000,0.090909,0.000000 +103.436733,0.163636,0.000000 +206.873466,0.181818,0.000000 +310.310199,0.181818,0.000000 +413.746932,0.236364,0.000000 +517.183665,0.236364,0.000000 +620.620397,0.272727,0.000000 +724.057130,0.300000,0.000000 +827.493863,0.318182,0.000000 +930.930596,0.345455,0.000000 +1034.367329,0.436364,0.000000 +1137.804062,0.490909,0.000000 +1241.240795,0.509091,0.000000 +1344.677528,0.536364,0.000000 +1448.114261,0.545455,0.000000 +1551.550994,0.572727,0.000000 +1654.987727,0.600000,0.000000 +1758.424459,0.627273,0.000000 +1861.861192,0.645455,0.000000 +1965.297925,0.663636,0.000000 +2068.734658,0.690909,0.000000 +2172.171391,0.709091,0.000000 +2275.608124,0.718182,0.000000 +2379.044857,0.736364,0.000000 +2482.481590,0.754545,0.000000 +2585.918323,0.754545,0.000000 +2689.355056,0.790909,0.000000 +2792.791788,0.818182,0.000000 +2896.228521,0.827273,0.000000 +2999.665254,0.827273,0.000000 +3103.101987,0.845455,0.000000 +3206.538720,0.854545,0.000000 +3309.975453,0.881818,0.000000 +3413.412186,0.881818,0.000000 +3516.848919,0.900000,0.000000 +3620.285652,0.909091,0.000000 +3723.722385,0.909091,0.000000 +3827.159118,0.927273,0.000000 +3930.595850,0.945455,0.000000 +4034.032583,0.945455,0.000000 +4137.469316,0.945455,0.000000 +4240.906049,0.945455,0.000000 +4344.342782,0.945455,0.000000 +4447.779515,0.945455,0.000000 +4551.216248,0.945455,0.000000 +4654.652981,0.945455,0.000000 +4758.089714,0.954545,0.000000 +4861.526447,0.954545,0.000000 +4964.963180,0.954545,0.000000 +5068.399912,0.954545,0.000000 +5171.836645,0.954545,0.000000 +5275.273378,0.954545,0.000000 +5378.710111,0.954545,0.000000 +5482.146844,0.954545,0.000000 +5585.583577,0.963636,0.000000 +5689.020310,0.963636,0.000000 +5792.457043,0.972727,0.000000 +5895.893776,0.972727,0.000000 +5999.330509,0.972727,0.000000 +6102.767241,0.981818,0.000000 +6206.203974,0.981818,0.000000 +6309.640707,0.981818,0.000000 +6413.077440,0.981818,0.000000 +6516.514173,0.981818,0.000000 +6619.950906,0.981818,0.000000 +6723.387639,0.981818,0.000000 +6826.824372,0.981818,0.000000 +6930.261105,0.981818,0.000000 +7033.697838,0.981818,0.000000 +7137.134571,0.981818,0.000000 +7240.571303,0.981818,0.000000 +7344.008036,0.981818,0.000000 +7447.444769,0.981818,0.000000 +7550.881502,0.981818,0.000000 +7654.318235,0.981818,0.000000 +7757.754968,0.981818,0.000000 +7861.191701,0.981818,0.000000 +7964.628434,0.981818,0.000000 +8068.065167,0.981818,0.000000 +8171.501900,0.981818,0.000000 +8274.938633,0.981818,0.000000 +8378.375365,0.981818,0.000000 +8481.812098,0.981818,0.000000 +8585.248831,0.981818,0.000000 +8688.685564,0.981818,0.000000 +8792.122297,0.981818,0.000000 +8895.559030,0.990909,0.000000 +8998.995763,0.990909,0.000000 +9102.432496,0.990909,0.000000 +9205.869229,0.990909,0.000000 +9309.305962,0.990909,0.000000 +9412.742694,0.990909,0.000000 +9516.179427,0.990909,0.000000 +9619.616160,0.990909,0.000000 +9723.052893,0.990909,0.000000 +9826.489626,0.990909,0.000000 +9929.926359,0.990909,0.000000 +10033.363092,0.990909,0.000000 +10136.799825,0.990909,0.000000 +10240.236558,0.990909,0.000000 diff --git a/vector/v.ppa/testsuite/outputs/g_crime.json b/vector/v.ppa/testsuite/outputs/g_crime.json new file mode 100644 index 00000000000..0967ef424bc --- /dev/null +++ b/vector/v.ppa/testsuite/outputs/g_crime.json @@ -0,0 +1 @@ +{} diff --git a/vector/v.ppa/testsuite/outputs/k_crime.csv b/vector/v.ppa/testsuite/outputs/k_crime.csv new file mode 100644 index 00000000000..8e3ca89b711 --- /dev/null +++ b/vector/v.ppa/testsuite/outputs/k_crime.csv @@ -0,0 +1,101 @@ +Distance,K-value +0.000000,0.000000 +325.287318,488646.686613 +650.574636,1172752.047871 +975.861954,2150045.421097 +1301.149272,5033060.872115 +1626.436590,9235422.376987 +1951.723909,12753678.520601 +2277.011227,18275386.079329 +2602.298545,24236875.656008 +2927.585863,31126793.937252 +3252.873181,37821253.543851 +3578.160499,45346412.517693 +3903.447817,51845413.449646 +4228.735135,59517166.429472 +4554.022453,67140054.740635 +4879.309771,75007266.395106 +5204.597090,82727884.043592 +5529.884408,92061035.757902 +5855.171726,100954405.454260 +6180.459044,110043233.825263 +6505.746362,119180926.864927 +6831.033680,127048138.519397 +7156.320998,135990372.884417 +7481.608316,143955313.876210 +7806.895634,153874841.614455 +8132.182952,163989828.027345 +8457.470271,175668483.837398 +8782.757589,183144778.142578 +9108.044907,190718801.785080 +9433.332225,199367848.138131 +9758.619543,208847593.858425 +10083.906861,219109174.277299 +10409.194179,229126431.352867 +10734.481497,237922071.711902 +11059.768815,247450682.100857 +11385.056133,258445232.549651 +11710.343452,268022707.607267 +12035.630770,277062671.309609 +12360.918088,285467394.319354 +12686.205406,295484651.394922 +13011.492724,304915532.446554 +13336.780042,313027067.444331 +13662.067360,320649955.755495 +13987.354678,328028520.723352 +14312.641996,335798003.040500 +14637.929314,343127703.339696 +14963.216633,351727885.024086 +15288.503951,359399638.003911 +15613.791269,365752044.929881 +15939.078587,371860128.512544 +16264.365905,376257948.692062 +16589.653223,382952408.298661 +16914.940541,387008175.797549 +17240.227859,393556041.398164 +17565.515177,396683380.192488 +17890.802495,402302817.088538 +18216.089814,405185832.539555 +18541.377132,407971118.653250 +18866.664450,410902998.772928 +19191.951768,414616713.591187 +19517.239086,417841781.722834 +19842.526404,421017985.185819 +20167.813722,424194188.648804 +20493.101040,427126068.768482 +20818.388358,429618166.870209 +21143.675676,432598911.658548 +21468.962994,434846686.416968 +21794.250313,438169483.885937 +22119.537631,440612717.319003 +22444.824949,441345687.348922 +22770.112267,442371845.390810 +23095.399585,443007086.083407 +23420.686903,444717349.486552 +23745.974221,445205996.173165 +24071.261539,445645778.191117 +24396.548857,446574206.895682 +24721.836175,447062853.582295 +25047.123494,447698094.274892 +25372.410812,447893552.949537 +25697.698130,448382199.636150 +26022.985448,449261763.672054 +26348.272766,449652681.021344 +26673.560084,449994733.701973 +26998.847402,450385651.051264 +27324.134720,450825433.069216 +27649.422038,451020891.743861 +27974.709356,451020891.743861 +28299.996675,451216350.418506 +28625.283993,451216350.418506 +28950.571311,451216350.418506 +29275.858629,451216350.418506 +29601.145947,451509538.430474 +29926.433265,451509538.430474 +30251.720583,451607267.767797 +30577.007901,451900455.779764 +30902.295219,451900455.779764 +31227.582537,451998185.117087 +31552.869856,452193643.791732 +31878.157174,452486831.803700 +32203.444492,452486831.803700 diff --git a/vector/v.ppa/testsuite/outputs/k_crime.json b/vector/v.ppa/testsuite/outputs/k_crime.json new file mode 100644 index 00000000000..38974d90847 --- /dev/null +++ b/vector/v.ppa/testsuite/outputs/k_crime.json @@ -0,0 +1,206 @@ +{ + "distance": [ + 0, + 325.28731809845124, + 650.57463619690247, + 975.86195429535371, + 1301.1492723938049, + 1626.4365904922561, + 1951.7239085907074, + 2277.0112266891588, + 2602.2985447876099, + 2927.585862886061, + 3252.8731809845121, + 3578.1604990829637, + 3903.4478171814148, + 4228.735135279866, + 4554.0224533783176, + 4879.3097714767682, + 5204.5970895752198, + 5529.8844076736714, + 5855.171725772122, + 6180.4590438705736, + 6505.7463619690243, + 6831.0336800674759, + 7156.3209981659274, + 7481.6083162643781, + 7806.8956343628297, + 8132.1829524612813, + 8457.4702705597319, + 8782.7575886581835, + 9108.0449067566351, + 9433.3322248550867, + 9758.6195429535364, + 10083.906861051988, + 10409.19417915044, + 10734.481497248891, + 11059.768815347343, + 11385.056133445793, + 11710.343451544244, + 12035.630769642696, + 12360.918087741147, + 12686.205405839599, + 13011.492723938049, + 13336.7800420365, + 13662.067360134952, + 13987.354678233403, + 14312.641996331855, + 14637.929314430306, + 14963.216632528756, + 15288.503950627208, + 15613.791268725659, + 15939.078586824111, + 16264.365904922563, + 16589.653223021014, + 16914.940541119464, + 17240.227859217917, + 17565.515177316367, + 17890.802495414817, + 18216.08981351327, + 18541.37713161172, + 18866.664449710173, + 19191.951767808623, + 19517.239085907073, + 19842.526404005526, + 20167.813722103976, + 20493.101040202429, + 20818.388358300879, + 21143.675676399329, + 21468.962994497782, + 21794.250312596232, + 22119.537630694686, + 22444.824948793135, + 22770.112266891585, + 23095.399584990038, + 23420.686903088488, + 23745.974221186942, + 24071.261539285391, + 24396.548857383841, + 24721.836175482294, + 25047.123493580744, + 25372.410811679198, + 25697.698129777647, + 26022.985447876097, + 26348.272765974551, + 26673.560084073, + 26998.847402171454, + 27324.134720269903, + 27649.422038368357, + 27974.709356466807, + 28299.996674565256, + 28625.28399266371, + 28950.57131076216, + 29275.858628860613, + 29601.145946959063, + 29926.433265057512, + 30251.720583155966, + 30577.007901254416, + 30902.295219352869, + 31227.582537451319, + 31552.869855549769, + 31878.157173648222, + 32203.444491746672 + ], + "k-value": [ + 0, + 488646.68661306711, + 1172752.047871361, + 2150045.4210974951, + 5033060.8721145913, + 9235422.3769869693, + 12753678.520601051, + 18275386.079328708, + 24236875.656008128, + 31126793.937252376, + 37821253.543851398, + 45346412.517692626, + 51845413.449646421, + 59517166.429471575, + 67140054.740635425, + 75007266.395105794, + 82727884.043592259, + 92061035.757901847, + 100954405.45425966, + 110043233.82526271, + 119180926.86492707, + 127048138.51939745, + 135990372.88441658, + 143955313.87620956, + 153874841.61445484, + 163989828.02734533, + 175668483.83739763, + 183144778.14257756, + 190718801.78508011, + 199367848.13813138, + 208847593.85842487, + 219109174.27729928, + 229126431.35286716, + 237922071.71190238, + 247450682.1008572, + 258445232.54965121, + 268022707.60726732, + 277062671.30960906, + 285467394.31935382, + 295484651.39492166, + 304915532.44655389, + 313027067.44433081, + 320649955.75549465, + 328028520.72335196, + 335798003.04049975, + 343127703.33969575, + 351727885.0240857, + 359399638.00391084, + 365752044.92988074, + 371860128.5125441, + 376257948.69206166, + 382952408.2986607, + 387008175.79754913, + 393556041.39816427, + 396683380.1924879, + 402302817.08853817, + 405185832.53955525, + 407971118.65324974, + 410902998.77292812, + 414616713.59118742, + 417841781.72283369, + 421017985.18581861, + 424194188.64880353, + 427126068.76848197, + 429618166.87020862, + 432598911.6585483, + 434846686.41696841, + 438169483.88593727, + 440612717.31900263, + 441345687.34892219, + 442371845.39080966, + 443007086.08340663, + 444717349.48655236, + 445205996.17316544, + 445645778.19111723, + 446574206.89568204, + 447062853.58229512, + 447698094.27489209, + 447893552.94953734, + 448382199.63615036, + 449261763.67205387, + 449652681.02134436, + 449994733.7019735, + 450385651.05126393, + 450825433.06921571, + 451020891.74386096, + 451020891.74386096, + 451216350.41850615, + 451216350.41850615, + 451216350.41850615, + 451216350.41850615, + 451509538.43047398, + 451509538.43047398, + 451607267.76779664, + 451900455.77976447, + 451900455.77976447, + 451998185.11708707, + 452193643.79173231, + 452486831.80370015, + 452486831.80370015 + ] +} diff --git a/vector/v.ppa/testsuite/outputs/l_crime.csv b/vector/v.ppa/testsuite/outputs/l_crime.csv new file mode 100644 index 00000000000..17b1c45acfe --- /dev/null +++ b/vector/v.ppa/testsuite/outputs/l_crime.csv @@ -0,0 +1,101 @@ +Distance,L-value +0.000000,0.000000 +325.287318,394.386956 +650.574636,610.981645 +975.861954,827.273058 +1301.149272,1265.730237 +1626.436590,1714.562990 +1951.723909,2014.850356 +2277.011227,2411.894704 +2602.298545,2777.559564 +2927.585863,3147.692208 +3252.873181,3469.708765 +3578.160499,3799.238267 +3903.447817,4062.377094 +4228.735135,4352.574235 +4554.022453,4622.915009 +4879.309771,4886.261805 +5204.597090,5131.579031 +5529.884408,5413.311169 +5855.171726,5668.755182 +6180.459044,5918.433005 +6505.746362,6159.258662 +6831.033680,6359.298586 +7156.320998,6579.291764 +7481.608316,6769.224444 +7806.895634,6998.562947 +8132.182952,7224.927923 +8457.470271,7477.768056 +8782.757589,7635.233689 +9108.044907,7791.513338 +9433.332225,7966.226023 +9758.619543,8153.419763 +10083.906861,8351.324226 +10409.194179,8540.094161 +10734.481497,8702.467901 +11059.768815,8875.021040 +11385.056133,9070.042589 +11710.343452,9236.572825 +12035.630770,9391.048257 +12360.918088,9532.423291 +12686.205406,9698.231063 +13011.492724,9851.783008 +13336.780042,9981.964246 +13662.067360,10102.774417 +13987.354678,10218.352171 +14312.641996,10338.656786 +14637.929314,10450.882269 +14963.216633,10581.042626 +15288.503951,10695.814970 +15613.791269,10789.925477 +15939.078587,10879.648670 +16264.365905,10943.793895 +16589.653223,11040.721783 +16914.940541,11099.032768 +17240.227859,11192.532276 +17565.515177,11236.914238 +17890.802495,11316.225692 +18216.089814,11356.700940 +18541.377132,11395.667613 +18866.664450,11436.541731 +19191.951768,11488.106846 +19517.239086,11532.700030 +19842.526404,11576.449669 +20167.813722,11620.034592 +20493.101040,11660.122226 +20818.388358,11694.088669 +21143.675676,11734.586074 +21468.962994,11765.032905 +21794.250313,11809.897482 +22119.537631,11842.777711 +22444.824949,11852.623993 +22770.112267,11866.395062 +23095.399585,11874.912006 +23420.686903,11897.811937 +23745.974221,11904.346684 +24071.261539,11910.224890 +24396.548857,11922.624919 +24721.836175,11929.146073 +25047.123494,11937.618248 +25372.410812,11940.223861 +25697.698130,11946.735409 +26022.985448,11958.447260 +26348.272766,11963.648846 +26673.560084,11968.198380 +26998.847402,11973.395731 +27324.134720,11979.240055 +27649.422038,11981.836617 +27974.709356,11981.836617 +28299.996675,11984.432617 +28625.283993,11984.432617 +28950.571311,11984.432617 +29275.858629,11984.432617 +29601.145947,11988.325562 +29926.433265,11988.325562 +30251.720583,11989.622930 +30577.007901,11993.514191 +30902.295219,11993.514191 +31227.582537,11994.810997 +31552.869856,11997.404190 +31878.157174,12001.292927 +32203.444492,12001.292927 diff --git a/vector/v.ppa/testsuite/outputs/l_crime.json b/vector/v.ppa/testsuite/outputs/l_crime.json new file mode 100644 index 00000000000..8f2e3851066 --- /dev/null +++ b/vector/v.ppa/testsuite/outputs/l_crime.json @@ -0,0 +1,206 @@ +{ + "distance": [ + 0, + 325.28731809845124, + 650.57463619690247, + 975.86195429535371, + 1301.1492723938049, + 1626.4365904922561, + 1951.7239085907074, + 2277.0112266891588, + 2602.2985447876099, + 2927.585862886061, + 3252.8731809845121, + 3578.1604990829637, + 3903.4478171814148, + 4228.735135279866, + 4554.0224533783176, + 4879.3097714767682, + 5204.5970895752198, + 5529.8844076736714, + 5855.171725772122, + 6180.4590438705736, + 6505.7463619690243, + 6831.0336800674759, + 7156.3209981659274, + 7481.6083162643781, + 7806.8956343628297, + 8132.1829524612813, + 8457.4702705597319, + 8782.7575886581835, + 9108.0449067566351, + 9433.3322248550867, + 9758.6195429535364, + 10083.906861051988, + 10409.19417915044, + 10734.481497248891, + 11059.768815347343, + 11385.056133445793, + 11710.343451544244, + 12035.630769642696, + 12360.918087741147, + 12686.205405839599, + 13011.492723938049, + 13336.7800420365, + 13662.067360134952, + 13987.354678233403, + 14312.641996331855, + 14637.929314430306, + 14963.216632528756, + 15288.503950627208, + 15613.791268725659, + 15939.078586824111, + 16264.365904922563, + 16589.653223021014, + 16914.940541119464, + 17240.227859217917, + 17565.515177316367, + 17890.802495414817, + 18216.08981351327, + 18541.37713161172, + 18866.664449710173, + 19191.951767808623, + 19517.239085907073, + 19842.526404005526, + 20167.813722103976, + 20493.101040202429, + 20818.388358300879, + 21143.675676399329, + 21468.962994497782, + 21794.250312596232, + 22119.537630694686, + 22444.824948793135, + 22770.112266891585, + 23095.399584990038, + 23420.686903088488, + 23745.974221186942, + 24071.261539285391, + 24396.548857383841, + 24721.836175482294, + 25047.123493580744, + 25372.410811679198, + 25697.698129777647, + 26022.985447876097, + 26348.272765974551, + 26673.560084073, + 26998.847402171454, + 27324.134720269903, + 27649.422038368357, + 27974.709356466807, + 28299.996674565256, + 28625.28399266371, + 28950.57131076216, + 29275.858628860613, + 29601.145946959063, + 29926.433265057512, + 30251.720583155966, + 30577.007901254416, + 30902.295219352869, + 31227.582537451319, + 31552.869855549769, + 31878.157173648222, + 32203.444491746672 + ], + "l-value": [ + 0, + 394.38695617361867, + 610.98164528874383, + 827.27305847557011, + 1265.7302371986243, + 1714.5629897084434, + 2014.8503563086706, + 2411.8947039362961, + 2777.5595639904168, + 3147.6922078616753, + 3469.70876456103, + 3799.2382667253132, + 4062.377094055711, + 4352.5742351103936, + 4622.9150092625687, + 4886.2618052232319, + 5131.5790312672461, + 5413.3111691514305, + 5668.7551816865098, + 5918.4330049613336, + 6159.2586620188004, + 6359.2985864772754, + 6579.2917639309708, + 6769.2244441655303, + 6998.5629468374391, + 7224.9279231480014, + 7477.7680558012171, + 7635.2336890051674, + 7791.5133375563046, + 7966.2260230021011, + 8153.4197629481678, + 8351.3242258956452, + 8540.0941614029798, + 8702.4679009593219, + 8875.0210397285937, + 9070.0425885230979, + 9236.5728250872726, + 9391.0482572681231, + 9532.4232907995029, + 9698.2310631668588, + 9851.7830075947422, + 9981.96424611162, + 10102.774417028671, + 10218.352171289038, + 10338.656785509695, + 10450.88226881176, + 10581.042625832397, + 10695.814969768337, + 10789.925476717577, + 10879.648670022285, + 10943.793895350767, + 11040.721783441299, + 11099.032768233199, + 11192.532275780708, + 11236.914238351746, + 11316.225692291178, + 11356.700939927507, + 11395.6676129479, + 11436.541731309733, + 11488.106846348019, + 11532.700030046195, + 11576.4496692996, + 11620.034591541717, + 11660.122226453093, + 11694.088669021836, + 11734.586074219415, + 11765.032905214661, + 11809.897482406144, + 11842.777710526465, + 11852.623992506566, + 11866.395061570387, + 11874.912005982273, + 11897.811937453942, + 11904.3466838891, + 11910.224890164809, + 11922.624919437041, + 11929.146073411166, + 11937.618247931239, + 11940.223861461762, + 11946.735409015333, + 11958.447259622821, + 11963.648846323618, + 11968.198380206621, + 11973.395730741564, + 11979.240054737204, + 11981.836617042487, + 11981.836617042487, + 11984.432616773316, + 11984.432616773316, + 11984.432616773316, + 11984.432616773316, + 11988.325562341892, + 11988.325562341892, + 11989.622929973237, + 11993.514190830807, + 11993.514190830807, + 11994.810997256269, + 11997.40418958951, + 12001.292927476599, + 12001.292927476599 + ] +} diff --git a/vector/v.ppa/testsuite/test_v_ppa.py b/vector/v.ppa/testsuite/test_v_ppa.py new file mode 100644 index 00000000000..49c4864c3c7 --- /dev/null +++ b/vector/v.ppa/testsuite/test_v_ppa.py @@ -0,0 +1,188 @@ +""" +Name: v.ppa test +Purpose: Tests v.ppa functions. +Author: Corey T. White +Copyright: (C) 2024 by Corey White and the GRASS Development Team +Licence: This program is free software under the GNU General Public + License (>=v2). Read the file COPYING that comes with GRASS + for details. +""" + +from grass.gunittest.case import TestCase + + +class TestPointPatternAnalysis(TestCase): + input = "crime" + + @classmethod + def setUpClass(cls): + cls.use_temp_region() + cls.runModule( + "v.import", + input="data/raleigh_crime_2022_2024.fgb", + output=cls.input, + overwrite=True, + ) + cls.runModule("g.region", vector=cls.input, res=30) + + @classmethod + def tearDownClass(cls): + cls.runModule("g.remove", type="vector", flags="f", name=cls.input) + cls.del_temp_region() + + def test_g_function_csv(self): + """Testing g function csv output""" + self.assertModule( + "v.ppa", + input=self.input, + output=f"outputs/g_{self.input}.csv", + method="g", + format="plain", + seed=1, + overwrite=True, + ) + + def test_g_function_json(self): + """Testing g function json output""" + self.assertModule( + "v.ppa", + input=self.input, + output=f"outputs/g_{self.input}.json", + method="g", + format="json", + seed=1, + overwrite=True, + ) + + def test_f_function_plain(self): + """Testing f function csv output""" + self.assertModule( + "v.ppa", + input=self.input, + output=f"outputs/f_{self.input}.csv", + method="f", + format="plain", + seed=1, + overwrite=True, + ) + + def test_f_function_json(self): + """Testing f function json output""" + self.assertModule( + "v.ppa", + input=self.input, + output=f"outputs/f_{self.input}.json", + method="f", + format="json", + seed=1, + overwrite=True, + ) + + def test_f_function_num_distances(self): + """Testing f function num_distance parameter""" + self.assertModule( + "v.ppa", + input=self.input, + output=f"outputs/g_{self.input}.json", + method="f", + format="json", + num_distances=400, + seed=1, + overwrite=True, + ) + + def test_f_function_random_points(self): + """Testing f function random points parameter""" + self.assertModule( + "v.ppa", + input=self.input, + output=f"outputs/g_{self.input}.json", + method="f", + format="json", + random_points=2000, + seed=1, + overwrite=True, + ) + + def test_k_function_plain(self): + """Testing k function csv output""" + self.assertModule( + "v.ppa", + input=self.input, + output=f"outputs/k_{self.input}.csv", + method="k", + format="plain", + seed=1, + overwrite=True, + ) + + def test_k_function_json(self): + """Testing k function json output""" + self.assertModule( + "v.ppa", + input=self.input, + # output=f"outputs/k_{self.input}.json", + method="k", + format="json", + seed=1, + overwrite=True, + ) + + def test_k_function_save_json_file(self): + """Testing k function json output""" + self.assertModule( + "v.ppa", + input=self.input, + output=f"outputs/k_{self.input}.json", + method="k", + format="json", + seed=1, + overwrite=True, + ) + + def test_l_function_plain(self): + """Testing l function csv output""" + self.assertModule( + "v.ppa", + input=self.input, + output=f"outputs/l_{self.input}.csv", + method="l", + random_points=100, + format="plain", + seed=1, + overwrite=True, + ) + + def test_l_function_json(self): + """Testing l function json output""" + self.assertModule( + "v.ppa", + input=self.input, + output=f"outputs/l_{self.input}.json", + method="l", + random_points=100, + format="json", + seed=1, + overwrite=True, + ) + + def test_simulation(self): + pass + + def test_monte_carlo_envelope(self): + pass + + def test_generate_random_points(self): + pass + + def test_euclidean_distance(self): + pass + + def test_max_distance(self): + pass + + +if __name__ == "__main__": + from grass.gunittest.main import test + + test() diff --git a/vector/v.ppa/v.ppa.html b/vector/v.ppa/v.ppa.html new file mode 100644 index 00000000000..f4d2c36004e --- /dev/null +++ b/vector/v.ppa/v.ppa.html @@ -0,0 +1,47 @@ +

DESCRIPTION

+ +v.ppa allows users to perform point pattern analysis with the G, F, K, L, and bivariate Ripley's K functions. + +

Notes

+ +

EXAMPLES

+ +

G Function

+Determine the distribution of distances from each point to its nearest neighbor to learn if the points are clustered, dispersed, or randomly distributed across the computational region. +
+   v.ppa input=crash output=crash_g.csv method=g
+
+ +
+

F Function

+Determine the distribution of the distances from random points in the computational region to the points in the input vector map. +This function is to determine if the points are clustered, dispersed, or randomly distributed across the computational region. +The output file will contain the distances from the random points to the +nearest crash location. +
+   v.ppa input=crash output=crash_f.csv method=f
+
+ +
+

K and L Functions

+Determine if the points are clustered, dispersed, or randomly distributed across spatial scales in the compuational region. +
+   v.ppa input=crash output=crash_k.csv method=k
+
+ +The L-Function is a transformation of the K-Function that allows for easier interpretation of the results. + +
    +
  • If L(r) is less than the expected value, the points are dispersed.
  • +
  • If L(r) is greater than the expected value, the points are clustered.
  • +
  • If L(r) is equal to the expected value, the points are randomly distributed (Poisson Process).
  • +
+ +
+   v.ppa input=crash output=crash_l.csv method=l
+
+ + +

AUTHORS

+Corey T. White, OpenPlains Inc. +
diff --git a/vector/v.ppa/v.ppa.md b/vector/v.ppa/v.ppa.md new file mode 100644 index 00000000000..c519caefe41 --- /dev/null +++ b/vector/v.ppa/v.ppa.md @@ -0,0 +1,45 @@ +## Description + +*v.ppa* allows users to perform point pattern analysis with the G, F, K, L, and bivariate Ripley's K functions. + +## Notes + +## Examples + +### G Function + +Determine the distribution of distances from each point to its nearest neighbor to learn if the points are clustered, dispersed, or randomly distributed across the computational region. + +```bash +v.ppa input=crash output=crash_g.csv method=g +``` + +### F Function + +Determine the distribution of the distances from random points in the computational region to the points in the input vector map. This function is to determine if the points are clustered, dispersed, or randomly distributed across the computational region. The output file will contain the distances from the random points to the nearest crash location. + +```bash +v.ppa input=crash output=crash_f.csv method=f +``` + +### K and L Functions + +Determine if the points are clustered, dispersed, or randomly distributed across spatial scales in the computational region. + +```bash +v.ppa input=crash output=crash_k.csv method=k +``` + +The *L-Function* is a transformation of the K-Function that allows for easier interpretation of the results. + +- If L(r) is less than the expected value, the points are dispersed. +- If L(r) is greater than the expected value, the points are clustered. +- If L(r) is equal to the expected value, the points are randomly distributed (Poisson Process). + +```bash +v.ppa input=crash output=crash_l.csv method=l +``` + +## Authors + +Corey T. White, OpenPlains Inc.