123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398 |
- /****************************************************************
- *
- * MODULE: v.net.centrality
- *
- * AUTHOR(S): Daniel Bundala
- *
- * PURPOSE: This module computes various centrality measures
- *
- * COPYRIGHT: (C) 2002-2005 by the GRASS Development Team
- *
- * This program is free software under the
- * GNU General Public License (>=v2).
- * Read the file COPYING that comes with GRASS
- * for details.
- *
- ****************************************************************/
- #include <stdio.h>
- #include <stdlib.h>
- #include <grass/gis.h>
- #include <grass/vector.h>
- #include <grass/glocale.h>
- #include <grass/dbmi.h>
- #include <grass/neta.h>
- /*Global variables */
- struct Option *deg_opt, *close_opt, *betw_opt, *eigen_opt;
- double *deg, *closeness, *betw, *eigen;
- /* Attribute table */
- dbString sql, tmp;
- dbDriver *driver;
- struct field_info *Fi;
- void append_string(dbString * string, char *s)
- {
- db_append_string(string, ", ");
- db_append_string(string, s);
- db_append_string(string, " double precision");
- }
- void append_double(dbString * string, double d)
- {
- char buf[50];
- sprintf(buf, ",%f", d);
- db_append_string(string, buf);
- }
- void process_node(int node, int cat)
- {
- char buf[2000];
- sprintf(buf, "INSERT INTO %s VALUES(%d", Fi->table, cat);
- db_set_string(&sql, buf);
- if (deg_opt->answer)
- append_double(&sql, deg[node]);
- if (close_opt->answer)
- append_double(&sql, closeness[node]);
- if (betw_opt->answer)
- append_double(&sql, betw[node]);
- if (eigen_opt->answer)
- append_double(&sql, eigen[node]);
- db_append_string(&sql, ")");
- if (db_execute_immediate(driver, &sql) != DB_OK) {
- db_close_database_shutdown_driver(driver);
- G_fatal_error(_("Cannot insert new record: %s"), db_get_string(&sql));
- }
- }
- int main(int argc, char *argv[])
- {
- struct Map_info In, Out;
- static struct line_pnts *Points;
- struct line_cats *Cats;
- struct GModule *module; /* GRASS module for parsing arguments */
- struct Option *map_in, *map_out;
- struct Option *cat_opt, *where_opt, *afield_opt, *nfield_opt, *abcol,
- *afcol, *ncol;
- struct Option *iter_opt, *error_opt;
- struct Flag *geo_f, *add_f;
- int chcat, with_z;
- int afield, nfield, mask_type;
- struct varray *varray;
- dglGraph_s *graph;
- int i, geo, nnodes, nlines, j, max_cat;
- char buf[2000], *covered;
- /* initialize GIS environment */
- G_gisinit(argv[0]); /* reads grass env, stores program name to G_program_name() */
- /* initialize module */
- module = G_define_module();
- G_add_keyword(_("vector"));
- G_add_keyword(_("network"));
- G_add_keyword(_("centrality measures"));
- module->description =
- _("Computes degree, centrality, betweeness, closeness and eigenvector "
- "centrality measures in the network.");
- /* Define the different options as defined in gis.h */
- map_in = G_define_standard_option(G_OPT_V_INPUT);
- afield_opt = G_define_standard_option(G_OPT_V_FIELD);
- afield_opt->key = "arc_layer";
- afield_opt->answer = "1";
- afield_opt->label = _("Arc layer");
- afield_opt->guisection = _("Cost");
- nfield_opt = G_define_standard_option(G_OPT_V_FIELD);
- nfield_opt->key = "node_layer";
- nfield_opt->answer = "2";
- nfield_opt->label = _("Node layer");
- nfield_opt->guisection = _("Cost");
- map_out = G_define_standard_option(G_OPT_V_OUTPUT);
- cat_opt = G_define_standard_option(G_OPT_V_CATS);
- cat_opt->guisection = _("Selection");
- where_opt = G_define_standard_option(G_OPT_DB_WHERE);
- where_opt->guisection = _("Selection");
- afcol = G_define_standard_option(G_OPT_DB_COLUMN);
- afcol->key = "arc_column";
- afcol->required = NO;
- afcol->description =
- _("Arc forward/both direction(s) cost column (number)");
- afcol->guisection = _("Cost");
- abcol = G_define_standard_option(G_OPT_DB_COLUMN);
- abcol->key = "arc_backward_column";
- abcol->required = NO;
- abcol->description = _("Arc backward direction cost column (number)");
- abcol->guisection = _("Cost");
- ncol = G_define_option();
- ncol->key = "node_column";
- ncol->type = TYPE_STRING;
- ncol->required = NO;
- ncol->description = _("Node cost column (number)");
- ncol->guisection = _("Cost");
- deg_opt = G_define_standard_option(G_OPT_DB_COLUMN);
- deg_opt->key = "degree";
- deg_opt->required = NO;
- deg_opt->description = _("Name of degree centrality column");
- deg_opt->guisection = _("Columns");
- close_opt = G_define_standard_option(G_OPT_DB_COLUMN);
- close_opt->key = "closeness";
- close_opt->required = NO;
- close_opt->description = _("Name of closeness centrality column");
- close_opt->guisection = _("Columns");
- betw_opt = G_define_standard_option(G_OPT_DB_COLUMN);
- betw_opt->key = "betweenness";
- betw_opt->required = NO;
- betw_opt->description = _("Name of betweenness centrality column");
- betw_opt->guisection = _("Columns");
- eigen_opt = G_define_standard_option(G_OPT_DB_COLUMN);
- eigen_opt->key = "eigenvector";
- eigen_opt->required = NO;
- eigen_opt->description = _("Name of eigenvector centrality column");
- eigen_opt->guisection = _("Columns");
- iter_opt = G_define_option();
- iter_opt->key = "iterations";
- iter_opt->answer = "1000";
- iter_opt->type = TYPE_INTEGER;
- iter_opt->required = NO;
- iter_opt->description =
- _("Maximum number of iterations to compute eigenvector centrality");
- error_opt = G_define_option();
- error_opt->key = "error";
- error_opt->answer = "0.1";
- error_opt->type = TYPE_DOUBLE;
- error_opt->required = NO;
- error_opt->description =
- _("Cumulative error tolerance for eigenvector centrality");
- geo_f = G_define_flag();
- geo_f->key = 'g';
- geo_f->description =
- _("Use geodesic calculation for longitude-latitude locations");
- add_f = G_define_flag();
- add_f->key = 'a';
- add_f->description = _("Add points on nodes");
- /* options and flags parser */
- if (G_parser(argc, argv))
- exit(EXIT_FAILURE);
- /* TODO: make an option for this */
- mask_type = GV_LINE | GV_BOUNDARY;
- Points = Vect_new_line_struct();
- Cats = Vect_new_cats_struct();
- Vect_check_input_output_name(map_in->answer, map_out->answer,
- G_FATAL_EXIT);
- Vect_set_open_level(2);
- if (1 > Vect_open_old(&In, map_in->answer, ""))
- G_fatal_error(_("Unable to open vector map <%s>"), map_in->answer);
- with_z = Vect_is_3d(&In);
- if (0 > Vect_open_new(&Out, map_out->answer, with_z)) {
- Vect_close(&In);
- G_fatal_error(_("Unable to create vector map <%s>"), map_out->answer);
- }
- if (geo_f->answer) {
- geo = 1;
- if (G_projection() != PROJECTION_LL)
- G_warning(_("The current projection is not longitude-latitude"));
- }
- else
- geo = 0;
- /* parse filter option and select appropriate lines */
- afield = Vect_get_field_number(&In, afield_opt->answer);
- nfield = Vect_get_field_number(&In, nfield_opt->answer);
- if (where_opt->answer || cat_opt->answer) {
- chcat = (NetA_initialise_varray(&In, afield, GV_POINT,
- where_opt->answer,
- cat_opt->answer, &varray) > 0);
- }
- else
- chcat = 0;
- /* Create table */
- Fi = Vect_default_field_info(&Out, 1, NULL, GV_1TABLE);
- Vect_map_add_dblink(&Out, 1, NULL, Fi->table, GV_KEY_COLUMN, Fi->database,
- Fi->driver);
- db_init_string(&sql);
- driver = db_start_driver_open_database(Fi->driver, Fi->database);
- if (driver == NULL)
- G_fatal_error(_("Unable to open database <%s> by driver <%s>"),
- Fi->database, Fi->driver);
- db_set_error_handler_driver(driver);
- db_init_string(&tmp);
- if (deg_opt->answer)
- append_string(&tmp, deg_opt->answer);
- if (close_opt->answer)
- append_string(&tmp, close_opt->answer);
- if (betw_opt->answer)
- append_string(&tmp, betw_opt->answer);
- if (eigen_opt->answer)
- append_string(&tmp, eigen_opt->answer);
- sprintf(buf,
- "create table %s(cat integer%s)", Fi->table, db_get_string(&tmp));
- db_set_string(&sql, buf);
- G_debug(2, "%s", db_get_string(&sql));
- if (db_execute_immediate(driver, &sql) != DB_OK) {
- G_fatal_error(_("Unable to create table: '%s'"), db_get_string(&sql));
- }
- if (db_create_index2(driver, Fi->table, GV_KEY_COLUMN) != DB_OK)
- G_warning(_("Cannot create index"));
- if (db_grant_on_table
- (driver, Fi->table, DB_PRIV_SELECT, DB_GROUP | DB_PUBLIC) != DB_OK)
- G_fatal_error(_("Cannot grant privileges on table <%s>"), Fi->table);
- db_begin_transaction(driver);
- Vect_copy_head_data(&In, &Out);
- Vect_hist_copy(&In, &Out);
- Vect_hist_command(&Out);
- if (0 != Vect_net_build_graph(&In, mask_type, afield, nfield, afcol->answer,
- abcol->answer, ncol->answer, geo, 0))
- G_fatal_error(_("Unable to build graph for vector map <%s>"), Vect_get_full_name(&In));
-
- graph = Vect_net_get_graph(&In);
- nnodes = dglGet_NodeCount(graph);
- deg = closeness = betw = eigen = NULL;
- covered = (char *)G_calloc(nnodes + 1, sizeof(char));
- if (!covered)
- G_fatal_error(_("Out of memory"));
- if (deg_opt->answer) {
- deg = (double *)G_calloc(nnodes + 1, sizeof(double));
- if (!deg)
- G_fatal_error(_("Out of memory"));
- }
- if (close_opt->answer) {
- closeness = (double *)G_calloc(nnodes + 1, sizeof(double));
- if (!closeness)
- G_fatal_error(_("Out of memory"));
- }
- if (betw_opt->answer) {
- betw = (double *)G_calloc(nnodes + 1, sizeof(double));
- if (!betw)
- G_fatal_error(_("Out of memory"));
- }
- if (eigen_opt->answer) {
- eigen = (double *)G_calloc(nnodes + 1, sizeof(double));
- if (!eigen)
- G_fatal_error(_("Out of memory"));
- }
- if (deg_opt->answer) {
- G_message(_("Computing degree centrality measure"));
- NetA_degree_centrality(graph, deg);
- }
- if (betw_opt->answer || close_opt->answer) {
- G_message(_("Computing betweenness and/or closeness centrality measure"));
- NetA_betweenness_closeness(graph, betw, closeness);
- if (closeness)
- for (i = 1; i <= nnodes; i++)
- closeness[i] /= (double)In.dgraph.cost_multip;
- }
- if (eigen_opt->answer) {
- G_message(_("Computing eigenvector centrality measure"));
- NetA_eigenvector_centrality(graph, atoi(iter_opt->answer),
- atof(error_opt->answer), eigen);
- }
- nlines = Vect_get_num_lines(&In);
- G_message(_("Writing data into the table..."));
- G_percent_reset();
- for (i = 1; i <= nlines; i++) {
- G_percent(i, nlines, 1);
- int type = Vect_read_line(&In, Points, Cats, i);
- if (type == GV_POINT && (!chcat || varray->c[i])) {
- int cat, node;
- if (!Vect_cat_get(Cats, nfield, &cat))
- continue;
- Vect_reset_cats(Cats);
- Vect_cat_set(Cats, 1, cat);
- Vect_write_line(&Out, type, Points, Cats);
- node = Vect_find_node(&In, Points->x[0], Points->y[0], Points->z[0], 0, 0);
- process_node(node, cat);
- covered[node] = 1;
- }
- }
- if (add_f->answer && !chcat) {
- max_cat = 0;
- for (i = 1; i <= nlines; i++) {
- Vect_read_line(&In, NULL, Cats, i);
- for (j = 0; j < Cats->n_cats; j++)
- if (Cats->cat[j] > max_cat)
- max_cat = Cats->cat[j];
- }
- max_cat++;
- for (i = 1; i <= nnodes; i++)
- if (!covered[i]) {
- Vect_reset_cats(Cats);
- Vect_cat_set(Cats, 1, max_cat);
- NetA_add_point_on_node(&In, &Out, i, Cats);
- process_node(i, max_cat);
- max_cat++;
- }
- }
- db_commit_transaction(driver);
- db_close_database_shutdown_driver(driver);
- G_free(covered);
- if (deg)
- G_free(deg);
- if (closeness)
- G_free(closeness);
- if (betw)
- G_free(betw);
- if (eigen)
- G_free(eigen);
- Vect_build(&Out);
- Vect_close(&In);
- Vect_close(&Out);
- exit(EXIT_SUCCESS);
- }
|