main.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398
  1. /****************************************************************
  2. *
  3. * MODULE: v.net.centrality
  4. *
  5. * AUTHOR(S): Daniel Bundala
  6. *
  7. * PURPOSE: This module computes various centrality measures
  8. *
  9. * COPYRIGHT: (C) 2002-2005 by the GRASS Development Team
  10. *
  11. * This program is free software under the
  12. * GNU General Public License (>=v2).
  13. * Read the file COPYING that comes with GRASS
  14. * for details.
  15. *
  16. ****************************************************************/
  17. #include <stdio.h>
  18. #include <stdlib.h>
  19. #include <grass/gis.h>
  20. #include <grass/vector.h>
  21. #include <grass/glocale.h>
  22. #include <grass/dbmi.h>
  23. #include <grass/neta.h>
  24. /*Global variables */
  25. struct Option *deg_opt, *close_opt, *betw_opt, *eigen_opt;
  26. double *deg, *closeness, *betw, *eigen;
  27. /* Attribute table */
  28. dbString sql, tmp;
  29. dbDriver *driver;
  30. struct field_info *Fi;
  31. void append_string(dbString * string, char *s)
  32. {
  33. db_append_string(string, ", ");
  34. db_append_string(string, s);
  35. db_append_string(string, " double precision");
  36. }
  37. void append_double(dbString * string, double d)
  38. {
  39. char buf[50];
  40. sprintf(buf, ",%f", d);
  41. db_append_string(string, buf);
  42. }
  43. void process_node(int node, int cat)
  44. {
  45. char buf[2000];
  46. sprintf(buf, "INSERT INTO %s VALUES(%d", Fi->table, cat);
  47. db_set_string(&sql, buf);
  48. if (deg_opt->answer)
  49. append_double(&sql, deg[node]);
  50. if (close_opt->answer)
  51. append_double(&sql, closeness[node]);
  52. if (betw_opt->answer)
  53. append_double(&sql, betw[node]);
  54. if (eigen_opt->answer)
  55. append_double(&sql, eigen[node]);
  56. db_append_string(&sql, ")");
  57. if (db_execute_immediate(driver, &sql) != DB_OK) {
  58. db_close_database_shutdown_driver(driver);
  59. G_fatal_error(_("Cannot insert new record: %s"), db_get_string(&sql));
  60. }
  61. }
  62. int main(int argc, char *argv[])
  63. {
  64. struct Map_info In, Out;
  65. static struct line_pnts *Points;
  66. struct line_cats *Cats;
  67. struct GModule *module; /* GRASS module for parsing arguments */
  68. struct Option *map_in, *map_out;
  69. struct Option *cat_opt, *where_opt, *afield_opt, *nfield_opt, *abcol,
  70. *afcol, *ncol;
  71. struct Option *iter_opt, *error_opt;
  72. struct Flag *geo_f, *add_f;
  73. int chcat, with_z;
  74. int afield, nfield, mask_type;
  75. struct varray *varray;
  76. dglGraph_s *graph;
  77. int i, geo, nnodes, nlines, j, max_cat;
  78. char buf[2000], *covered;
  79. /* initialize GIS environment */
  80. G_gisinit(argv[0]); /* reads grass env, stores program name to G_program_name() */
  81. /* initialize module */
  82. module = G_define_module();
  83. G_add_keyword(_("vector"));
  84. G_add_keyword(_("network"));
  85. G_add_keyword(_("centrality measures"));
  86. module->description =
  87. _("Computes degree, centrality, betweeness, closeness and eigenvector "
  88. "centrality measures in the network.");
  89. /* Define the different options as defined in gis.h */
  90. map_in = G_define_standard_option(G_OPT_V_INPUT);
  91. afield_opt = G_define_standard_option(G_OPT_V_FIELD);
  92. afield_opt->key = "arc_layer";
  93. afield_opt->answer = "1";
  94. afield_opt->label = _("Arc layer");
  95. afield_opt->guisection = _("Cost");
  96. nfield_opt = G_define_standard_option(G_OPT_V_FIELD);
  97. nfield_opt->key = "node_layer";
  98. nfield_opt->answer = "2";
  99. nfield_opt->label = _("Node layer");
  100. nfield_opt->guisection = _("Cost");
  101. map_out = G_define_standard_option(G_OPT_V_OUTPUT);
  102. cat_opt = G_define_standard_option(G_OPT_V_CATS);
  103. cat_opt->guisection = _("Selection");
  104. where_opt = G_define_standard_option(G_OPT_DB_WHERE);
  105. where_opt->guisection = _("Selection");
  106. afcol = G_define_standard_option(G_OPT_DB_COLUMN);
  107. afcol->key = "arc_column";
  108. afcol->required = NO;
  109. afcol->description =
  110. _("Arc forward/both direction(s) cost column (number)");
  111. afcol->guisection = _("Cost");
  112. abcol = G_define_standard_option(G_OPT_DB_COLUMN);
  113. abcol->key = "arc_backward_column";
  114. abcol->required = NO;
  115. abcol->description = _("Arc backward direction cost column (number)");
  116. abcol->guisection = _("Cost");
  117. ncol = G_define_option();
  118. ncol->key = "node_column";
  119. ncol->type = TYPE_STRING;
  120. ncol->required = NO;
  121. ncol->description = _("Node cost column (number)");
  122. ncol->guisection = _("Cost");
  123. deg_opt = G_define_standard_option(G_OPT_DB_COLUMN);
  124. deg_opt->key = "degree";
  125. deg_opt->required = NO;
  126. deg_opt->description = _("Name of degree centrality column");
  127. deg_opt->guisection = _("Columns");
  128. close_opt = G_define_standard_option(G_OPT_DB_COLUMN);
  129. close_opt->key = "closeness";
  130. close_opt->required = NO;
  131. close_opt->description = _("Name of closeness centrality column");
  132. close_opt->guisection = _("Columns");
  133. betw_opt = G_define_standard_option(G_OPT_DB_COLUMN);
  134. betw_opt->key = "betweenness";
  135. betw_opt->required = NO;
  136. betw_opt->description = _("Name of betweenness centrality column");
  137. betw_opt->guisection = _("Columns");
  138. eigen_opt = G_define_standard_option(G_OPT_DB_COLUMN);
  139. eigen_opt->key = "eigenvector";
  140. eigen_opt->required = NO;
  141. eigen_opt->description = _("Name of eigenvector centrality column");
  142. eigen_opt->guisection = _("Columns");
  143. iter_opt = G_define_option();
  144. iter_opt->key = "iterations";
  145. iter_opt->answer = "1000";
  146. iter_opt->type = TYPE_INTEGER;
  147. iter_opt->required = NO;
  148. iter_opt->description =
  149. _("Maximum number of iterations to compute eigenvector centrality");
  150. error_opt = G_define_option();
  151. error_opt->key = "error";
  152. error_opt->answer = "0.1";
  153. error_opt->type = TYPE_DOUBLE;
  154. error_opt->required = NO;
  155. error_opt->description =
  156. _("Cumulative error tolerance for eigenvector centrality");
  157. geo_f = G_define_flag();
  158. geo_f->key = 'g';
  159. geo_f->description =
  160. _("Use geodesic calculation for longitude-latitude locations");
  161. add_f = G_define_flag();
  162. add_f->key = 'a';
  163. add_f->description = _("Add points on nodes");
  164. /* options and flags parser */
  165. if (G_parser(argc, argv))
  166. exit(EXIT_FAILURE);
  167. /* TODO: make an option for this */
  168. mask_type = GV_LINE | GV_BOUNDARY;
  169. Points = Vect_new_line_struct();
  170. Cats = Vect_new_cats_struct();
  171. Vect_check_input_output_name(map_in->answer, map_out->answer,
  172. G_FATAL_EXIT);
  173. Vect_set_open_level(2);
  174. if (1 > Vect_open_old(&In, map_in->answer, ""))
  175. G_fatal_error(_("Unable to open vector map <%s>"), map_in->answer);
  176. with_z = Vect_is_3d(&In);
  177. if (0 > Vect_open_new(&Out, map_out->answer, with_z)) {
  178. Vect_close(&In);
  179. G_fatal_error(_("Unable to create vector map <%s>"), map_out->answer);
  180. }
  181. if (geo_f->answer) {
  182. geo = 1;
  183. if (G_projection() != PROJECTION_LL)
  184. G_warning(_("The current projection is not longitude-latitude"));
  185. }
  186. else
  187. geo = 0;
  188. /* parse filter option and select appropriate lines */
  189. afield = Vect_get_field_number(&In, afield_opt->answer);
  190. nfield = Vect_get_field_number(&In, nfield_opt->answer);
  191. if (where_opt->answer || cat_opt->answer) {
  192. chcat = (NetA_initialise_varray(&In, afield, GV_POINT,
  193. where_opt->answer,
  194. cat_opt->answer, &varray) > 0);
  195. }
  196. else
  197. chcat = 0;
  198. /* Create table */
  199. Fi = Vect_default_field_info(&Out, 1, NULL, GV_1TABLE);
  200. Vect_map_add_dblink(&Out, 1, NULL, Fi->table, GV_KEY_COLUMN, Fi->database,
  201. Fi->driver);
  202. db_init_string(&sql);
  203. driver = db_start_driver_open_database(Fi->driver, Fi->database);
  204. if (driver == NULL)
  205. G_fatal_error(_("Unable to open database <%s> by driver <%s>"),
  206. Fi->database, Fi->driver);
  207. db_set_error_handler_driver(driver);
  208. db_init_string(&tmp);
  209. if (deg_opt->answer)
  210. append_string(&tmp, deg_opt->answer);
  211. if (close_opt->answer)
  212. append_string(&tmp, close_opt->answer);
  213. if (betw_opt->answer)
  214. append_string(&tmp, betw_opt->answer);
  215. if (eigen_opt->answer)
  216. append_string(&tmp, eigen_opt->answer);
  217. sprintf(buf,
  218. "create table %s(cat integer%s)", Fi->table, db_get_string(&tmp));
  219. db_set_string(&sql, buf);
  220. G_debug(2, "%s", db_get_string(&sql));
  221. if (db_execute_immediate(driver, &sql) != DB_OK) {
  222. G_fatal_error(_("Unable to create table: '%s'"), db_get_string(&sql));
  223. }
  224. if (db_create_index2(driver, Fi->table, GV_KEY_COLUMN) != DB_OK)
  225. G_warning(_("Cannot create index"));
  226. if (db_grant_on_table
  227. (driver, Fi->table, DB_PRIV_SELECT, DB_GROUP | DB_PUBLIC) != DB_OK)
  228. G_fatal_error(_("Cannot grant privileges on table <%s>"), Fi->table);
  229. db_begin_transaction(driver);
  230. Vect_copy_head_data(&In, &Out);
  231. Vect_hist_copy(&In, &Out);
  232. Vect_hist_command(&Out);
  233. if (0 != Vect_net_build_graph(&In, mask_type, afield, nfield, afcol->answer,
  234. abcol->answer, ncol->answer, geo, 0))
  235. G_fatal_error(_("Unable to build graph for vector map <%s>"), Vect_get_full_name(&In));
  236. graph = Vect_net_get_graph(&In);
  237. nnodes = dglGet_NodeCount(graph);
  238. deg = closeness = betw = eigen = NULL;
  239. covered = (char *)G_calloc(nnodes + 1, sizeof(char));
  240. if (!covered)
  241. G_fatal_error(_("Out of memory"));
  242. if (deg_opt->answer) {
  243. deg = (double *)G_calloc(nnodes + 1, sizeof(double));
  244. if (!deg)
  245. G_fatal_error(_("Out of memory"));
  246. }
  247. if (close_opt->answer) {
  248. closeness = (double *)G_calloc(nnodes + 1, sizeof(double));
  249. if (!closeness)
  250. G_fatal_error(_("Out of memory"));
  251. }
  252. if (betw_opt->answer) {
  253. betw = (double *)G_calloc(nnodes + 1, sizeof(double));
  254. if (!betw)
  255. G_fatal_error(_("Out of memory"));
  256. }
  257. if (eigen_opt->answer) {
  258. eigen = (double *)G_calloc(nnodes + 1, sizeof(double));
  259. if (!eigen)
  260. G_fatal_error(_("Out of memory"));
  261. }
  262. if (deg_opt->answer) {
  263. G_message(_("Computing degree centrality measure"));
  264. NetA_degree_centrality(graph, deg);
  265. }
  266. if (betw_opt->answer || close_opt->answer) {
  267. G_message(_("Computing betweenness and/or closeness centrality measure"));
  268. NetA_betweenness_closeness(graph, betw, closeness);
  269. if (closeness)
  270. for (i = 1; i <= nnodes; i++)
  271. closeness[i] /= (double)In.dgraph.cost_multip;
  272. }
  273. if (eigen_opt->answer) {
  274. G_message(_("Computing eigenvector centrality measure"));
  275. NetA_eigenvector_centrality(graph, atoi(iter_opt->answer),
  276. atof(error_opt->answer), eigen);
  277. }
  278. nlines = Vect_get_num_lines(&In);
  279. G_message(_("Writing data into the table..."));
  280. G_percent_reset();
  281. for (i = 1; i <= nlines; i++) {
  282. G_percent(i, nlines, 1);
  283. int type = Vect_read_line(&In, Points, Cats, i);
  284. if (type == GV_POINT && (!chcat || varray->c[i])) {
  285. int cat, node;
  286. if (!Vect_cat_get(Cats, nfield, &cat))
  287. continue;
  288. Vect_reset_cats(Cats);
  289. Vect_cat_set(Cats, 1, cat);
  290. Vect_write_line(&Out, type, Points, Cats);
  291. node = Vect_find_node(&In, Points->x[0], Points->y[0], Points->z[0], 0, 0);
  292. process_node(node, cat);
  293. covered[node] = 1;
  294. }
  295. }
  296. if (add_f->answer && !chcat) {
  297. max_cat = 0;
  298. for (i = 1; i <= nlines; i++) {
  299. Vect_read_line(&In, NULL, Cats, i);
  300. for (j = 0; j < Cats->n_cats; j++)
  301. if (Cats->cat[j] > max_cat)
  302. max_cat = Cats->cat[j];
  303. }
  304. max_cat++;
  305. for (i = 1; i <= nnodes; i++)
  306. if (!covered[i]) {
  307. Vect_reset_cats(Cats);
  308. Vect_cat_set(Cats, 1, max_cat);
  309. NetA_add_point_on_node(&In, &Out, i, Cats);
  310. process_node(i, max_cat);
  311. max_cat++;
  312. }
  313. }
  314. db_commit_transaction(driver);
  315. db_close_database_shutdown_driver(driver);
  316. G_free(covered);
  317. if (deg)
  318. G_free(deg);
  319. if (closeness)
  320. G_free(closeness);
  321. if (betw)
  322. G_free(betw);
  323. if (eigen)
  324. G_free(eigen);
  325. Vect_build(&Out);
  326. Vect_close(&In);
  327. Vect_close(&Out);
  328. exit(EXIT_SUCCESS);
  329. }