daemon.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631
  1. /**
  2. * \file daemon.c
  3. *
  4. * \brief Implementation of the server for parallel
  5. * computing of r.li raster analysis
  6. *
  7. * \author Claudio Porta & Lucio Davide Spano
  8. *
  9. * This program is free software under the GPL (>=v2)
  10. * Read the COPYING file that comes with GRASS for details.
  11. *
  12. * \version 1.0
  13. *
  14. * \include
  15. *
  16. */
  17. #include <grass/config.h>
  18. #include <stdlib.h>
  19. #include <stddef.h>
  20. #include <fcntl.h>
  21. #include <sys/types.h>
  22. #include <sys/stat.h>
  23. #include <dirent.h>
  24. #include <errno.h>
  25. #include <math.h>
  26. #ifdef __MINGW32__
  27. #include <process.h>
  28. #else
  29. #include <sys/wait.h>
  30. #endif
  31. #include <grass/gis.h>
  32. #include <grass/raster.h>
  33. #include <grass/glocale.h>
  34. #include "daemon.h"
  35. #ifdef __MINGW32__
  36. #define srandom srand
  37. #define random rand
  38. #endif
  39. int calculateIndex(char *file, int f(int, char **, struct area_entry *, double *),
  40. char **parameters, char *raster, char *output)
  41. {
  42. char pathSetup[GPATH_MAX], out[GPATH_MAX], parsed;
  43. char *random_access_name;
  44. struct History history;
  45. struct g_area *g;
  46. int res;
  47. int i, doneDir, mv_fd, random_access;
  48. /*int mv_rows, mv_cols; */
  49. struct list *l;
  50. msg m, doneJob;
  51. /* int perc=0; */
  52. g = (struct g_area *) G_malloc(sizeof(struct g_area));
  53. g->maskname = NULL;
  54. l = (struct list*) G_malloc(sizeof(struct list));
  55. l->head = NULL;
  56. l->tail = NULL;
  57. l->size = 0;
  58. worker_init(raster, f, parameters);
  59. /*########################################################
  60. -----------------create area queue----------------------
  61. ######################################################### */
  62. /* strip off leading path if present */
  63. char testpath[GPATH_MAX];
  64. sprintf(testpath, "%s%s", G_home(), "/.grass7/r.li/");
  65. if (strncmp(file, testpath, strlen(testpath)) == 0)
  66. file += strlen(testpath);
  67. /* TODO: check if this path is portable */
  68. /* TODO: use G_rc_path() */
  69. sprintf(pathSetup, "%s/.grass7/r.li/%s", G_home(), file);
  70. G_debug(1, "r.li.daemon pathSetup: [%s]", pathSetup);
  71. parsed = parseSetup(pathSetup, l, g, raster);
  72. /*########################################################
  73. -----------------open output file ---------------------
  74. ####################################################### */
  75. if (parsed == MVWIN) {
  76. /* struct Cell_head cellhd_r, cellhd_new;
  77. char *mapset; */
  78. /*creating new raster file */
  79. mv_fd = Rast_open_new(output, DCELL_TYPE);
  80. random_access_name = G_tempfile();
  81. random_access = open(random_access_name, O_RDWR | O_CREAT, 0755);
  82. if (random_access == -1)
  83. G_fatal_error(_("Cannot create random access file"));
  84. }
  85. else {
  86. /* check if ~/.grass7/ exists */
  87. sprintf(out, "%s/.grass7/", G_home());
  88. doneDir = G_mkdir(out);
  89. if (doneDir == -1 && errno != EEXIST)
  90. G_fatal_error(_("Cannot create %s/.grass7/ directory"), G_home());
  91. /* check if ~/.grass7/r.li/ exists */
  92. sprintf(out, "%s/.grass7/r.li/", G_home());
  93. doneDir = G_mkdir(out);
  94. if (doneDir == -1 && errno != EEXIST)
  95. G_fatal_error(_("Cannot create %s/.grass7/r.li/ directory"),
  96. G_home());
  97. /* check if ~/.grass7/r.li/output exists */
  98. sprintf(out, "%s/.grass7/r.li/output", G_home());
  99. doneDir = G_mkdir(out);
  100. if (doneDir == -1 && errno != EEXIST)
  101. G_fatal_error(_("Cannot create %s/.grass7/r.li/output/ directory"),
  102. G_home());
  103. sprintf(out, "%s/.grass7/r.li/output/%s", G_home(), output);
  104. res = open(out, O_WRONLY | O_CREAT | O_TRUNC, 0644);
  105. }
  106. i = 0;
  107. /*#######################################################
  108. ------------------analysis loop----------------------
  109. ####################################################### */
  110. /*body */
  111. while (next_Area(parsed, l, g, &m) != 0) {
  112. worker_process(&doneJob, &m);
  113. /*perc++; */
  114. /*G_percent (perc, WORKERS, 1); */
  115. if (doneJob.type == DONE) {
  116. double result;
  117. result = doneJob.f.f_d.res;
  118. /*output */
  119. if (parsed != MVWIN) {
  120. print_Output(res, doneJob);
  121. }
  122. else {
  123. /*raster output */
  124. raster_Output(random_access, doneJob.f.f_d.aid, g,
  125. doneJob.f.f_d.res);
  126. }
  127. }
  128. else {
  129. if (parsed != MVWIN) {
  130. error_Output(res, doneJob);
  131. }
  132. else {
  133. /*printf("todo ");fflush(stdout); *//* TODO scrivere su raster NULL ??? */
  134. }
  135. }
  136. }
  137. worker_end();
  138. /*################################################
  139. --------------delete tmp files------------------
  140. ################################################ */
  141. if (parsed == MVWIN) {
  142. write_raster(mv_fd, random_access, g);
  143. close(random_access);
  144. unlink(random_access_name);
  145. Rast_close(mv_fd);
  146. Rast_short_history(output, "raster", &history);
  147. Rast_command_history(&history);
  148. Rast_write_history(output, &history);
  149. }
  150. return 1;
  151. }
  152. int parseSetup(char *path, struct list *l, struct g_area *g, char *raster)
  153. {
  154. STRUCT_STAT s;
  155. struct Cell_head cellhd;
  156. char *buf;
  157. const char *token;
  158. int setup;
  159. int letti;
  160. double rel_x, rel_y, rel_rl, rel_cl;
  161. double sf_n, sf_s, sf_e, sf_w;
  162. int sf_x, sf_y, sf_rl, sf_cl;
  163. int size;
  164. if (stat(path, &s) != 0)
  165. G_fatal_error(_("Cannot find configuration file <%s>"), path);
  166. size = s.st_size * sizeof(char);
  167. buf = G_malloc(size);
  168. setup = open(path, O_RDONLY, 0755);
  169. if (setup == -1)
  170. G_fatal_error(_("Cannot read setup file"));
  171. letti = read(setup, buf, s.st_size);
  172. if (letti < s.st_size)
  173. G_fatal_error(_("Cannot read setup file"));
  174. token = strtok(buf, " ");
  175. if (strcmp("SAMPLINGFRAME", token) != 0)
  176. G_fatal_error(_("Unable to parse configuration file"));
  177. rel_x = atof(strtok(NULL, "|"));
  178. rel_y = atof(strtok(NULL, "|"));
  179. rel_rl = atof(strtok(NULL, "|"));
  180. rel_cl = atof(strtok(NULL, "\n"));
  181. /* find raster map */
  182. Rast_get_cellhd(raster, "", &cellhd);
  183. /* calculate absolute sampling frame definition */
  184. sf_x = (int)rint(cellhd.cols * rel_x);
  185. sf_y = (int)rint(cellhd.rows * rel_y);
  186. sf_rl = (int)rint(cellhd.rows * rel_rl);
  187. sf_cl = (int)rint(cellhd.cols * rel_cl);
  188. /* calculate sample frame boundaries */
  189. sf_n = cellhd.north - (cellhd.ns_res * sf_y);
  190. sf_s = sf_n - (cellhd.ns_res * sf_rl);
  191. sf_w = cellhd.west + (cellhd.ew_res * sf_x);
  192. sf_e = sf_w + (cellhd.ew_res * sf_cl);
  193. /* parse configuration file */
  194. token = strtok(NULL, " ");
  195. if (strcmp("SAMPLEAREA", token) == 0) {
  196. double rel_sa_x, rel_sa_y, rel_sa_rl, rel_sa_cl;
  197. int aid = 1, toReturn;
  198. do {
  199. rel_sa_x = atof(strtok(NULL, "|"));
  200. rel_sa_y = atof(strtok(NULL, "|"));
  201. rel_sa_rl = atof(strtok(NULL, "|"));
  202. rel_sa_cl = atof(strtok(NULL, "\n"));
  203. if (rel_sa_x == -1.0 && rel_sa_y == -1.0) {
  204. /* runtime disposition */
  205. int sa_rl, sa_cl;
  206. sa_rl = (int)rint(cellhd.rows * rel_sa_rl);
  207. sa_cl = (int)rint(cellhd.cols * rel_sa_cl);
  208. g->rows = sf_rl;
  209. g->cols = sf_cl;
  210. g->rl = sa_rl;
  211. g->cl = sa_cl;
  212. g->count = 1;
  213. g->sf_x = sf_x;
  214. g->sf_y = sf_y;
  215. g->x = sf_x;
  216. g->y = sf_y;
  217. g->maskname = NULL;
  218. return disposeAreas(l, g, strtok(NULL, "\n"));
  219. }
  220. else {
  221. msg m;
  222. toReturn = NORMAL;
  223. /*read file and create list */
  224. m.type = AREA;
  225. m.f.f_a.x = (int)rint(cellhd.cols * rel_sa_x);
  226. m.f.f_a.y = (int)rint(cellhd.rows * rel_sa_y);
  227. m.f.f_a.rl = (int)rint(cellhd.rows * rel_sa_rl);
  228. m.f.f_a.cl = (int)rint(cellhd.cols * rel_sa_cl);
  229. m.f.f_a.aid = aid;
  230. aid++;
  231. insertNode(l, m);
  232. }
  233. } while ((token = strtok(NULL, " ")) != NULL &&
  234. strcmp(token, "SAMPLEAREA") == 0);
  235. close(setup);
  236. return toReturn;
  237. }
  238. else if (strcmp("MASKEDSAMPLEAREA", token) == 0) {
  239. double rel_sa_x, rel_sa_y, rel_sa_rl, rel_sa_cl;
  240. int aid = 1;
  241. char maskname[GNAME_MAX];
  242. do {
  243. rel_sa_x = atof(strtok(NULL, "|"));
  244. rel_sa_y = atof(strtok(NULL, "|"));
  245. rel_sa_rl = atof(strtok(NULL, "|"));
  246. rel_sa_cl = atof(strtok(NULL, "|"));
  247. strcpy(maskname, strtok(NULL, "\n"));
  248. if (rel_sa_x == -1 && rel_sa_y == -1) {
  249. /* runtime disposition */
  250. int sa_rl, sa_cl;
  251. sa_rl = (int)rint(cellhd.rows * rel_sa_rl);
  252. sa_cl = (int)rint(cellhd.cols * rel_sa_cl);
  253. g->rows = sf_rl;
  254. g->cols = sf_cl;
  255. g->rl = sa_rl;
  256. g->cl = sa_cl;
  257. g->count = 1;
  258. g->x = sf_x;
  259. g->y = sf_y;
  260. g->maskname = maskname;
  261. return disposeAreas(l, g, strtok(NULL, "\n"));
  262. }
  263. else {
  264. /*read file and create list */
  265. msg m;
  266. m.type = MASKEDAREA;
  267. m.f.f_ma.x = (int)rint(cellhd.cols * rel_sa_x);
  268. m.f.f_ma.y = (int)rint(cellhd.rows * rel_sa_y);
  269. m.f.f_ma.rl = (int)rint(cellhd.rows * rel_sa_rl);
  270. m.f.f_ma.cl = (int)rint(cellhd.cols * rel_sa_cl);
  271. m.f.f_ma.aid = aid;
  272. strcpy(m.f.f_ma.mask, maskname);
  273. aid++;
  274. insertNode(l, m);
  275. }
  276. }
  277. while ((token = strtok(NULL, " ")) != NULL &&
  278. strcmp(token, "MASKEDSAMPLEAREA") == 0);
  279. close(setup);
  280. return NORMAL;
  281. }
  282. else if (strcmp("MASKEDOVERLAYAREA", token) == 0) {
  283. double sa_n, sa_s, sa_w, sa_e;
  284. int aid = 1;
  285. char maskname[GNAME_MAX];
  286. msg m;
  287. do {
  288. strcpy(maskname, strtok(NULL, "|"));
  289. sa_n = atof(strtok(NULL, "|"));
  290. sa_s = atof(strtok(NULL, "|"));
  291. sa_e = atof(strtok(NULL, "|"));
  292. sa_w = atof(strtok(NULL, "\n"));
  293. m.type = MASKEDAREA;
  294. m.f.f_ma.x = (int)rint((cellhd.north - sa_n) * cellhd.ns_res);
  295. m.f.f_ma.y = (int)rint((cellhd.west + sa_w) * cellhd.ew_res);
  296. m.f.f_ma.rl = (int)rint((sa_n - sa_s) * cellhd.ns_res);
  297. m.f.f_ma.cl = (int)rint((sa_e - sa_w) * cellhd.ew_res);
  298. m.f.f_ma.aid = aid;
  299. strcpy(m.f.f_ma.mask, maskname);
  300. aid++;
  301. insertNode(l, m);
  302. }
  303. while ((token = strtok(NULL, " ")) != NULL &&
  304. (strcmp(token, "MASKEDOVERLAYAREA") == 0));
  305. if (strcmp(token, "RASTERMAP") != 0)
  306. G_fatal_error(_("Irregular maskedoverlay areas definition"));
  307. token = strtok(NULL, "\n");
  308. if (strcmp(token, raster) != 0)
  309. G_fatal_error(_("The configuration file can be used only with \
  310. %s rasterfile"), token);
  311. close(setup);
  312. return NORMAL;
  313. }
  314. else
  315. G_fatal_error(_("Illegal configuration file (sample area)"));
  316. close(setup);
  317. return ERROR;
  318. }
  319. int disposeAreas(struct list *l, struct g_area *g, char *def)
  320. {
  321. char *token;
  322. token = strtok(def, " \n");
  323. if (strcmp(token, "MOVINGWINDOW") == 0) {
  324. g->count = 0;
  325. g->dist = 0;
  326. g->add_row = 1;
  327. g->add_col = 1;
  328. if (g->rl != 1)
  329. g->rows = g->rows - g->rl + 1;
  330. else
  331. g->rows = g->rows;
  332. if (g->cl != 1)
  333. g->cols = g->cols - g->cl + 1;
  334. return MVWIN;
  335. }
  336. else if (strcmp(token, "RANDOMNONOVERLAPPING") == 0) {
  337. int units, sf_rl, sf_cl, sa_rl, sa_cl, max_units, i;
  338. int *assigned;
  339. sscanf(strtok(NULL, "\n"), "%i", &units);
  340. sf_rl = g->rows;
  341. sf_cl = g->cols;
  342. sa_rl = g->rl;
  343. sa_cl = g->cl;
  344. max_units = (int)rint((sf_rl / sa_rl) * (sf_cl / sa_cl));
  345. if (units > max_units)
  346. G_fatal_error(_("Too many units to place"));
  347. assigned = G_malloc(units * sizeof(int));
  348. i = 0;
  349. srandom(0);
  350. while (i < units) {
  351. int j, position, found = FALSE;
  352. position = random() % max_units;
  353. for (j = 0; j < i; j++) {
  354. if (assigned[j] == position)
  355. found = TRUE;
  356. }
  357. if (!found) {
  358. msg m;
  359. assigned[i] = position;
  360. i++;
  361. if (g->maskname == NULL) {
  362. int n_col = rint(sf_cl / sa_cl);
  363. m.type = AREA;
  364. m.f.f_a.aid = i;
  365. m.f.f_a.x = g->sf_x + (position % n_col) * sa_cl;
  366. m.f.f_a.y = g->sf_y + (position / n_col) * sa_rl;
  367. m.f.f_a.rl = sa_rl;
  368. m.f.f_a.cl = sa_cl;
  369. insertNode(l, m);
  370. }
  371. else {
  372. int n_col = sf_cl / sa_cl;
  373. m.type = MASKEDAREA;
  374. m.f.f_ma.aid = i;
  375. m.f.f_a.x = g->sf_x + (position % n_col) * sa_cl;
  376. m.f.f_a.y = g->sf_y + (position / n_col) * sa_rl;
  377. m.f.f_ma.rl = sa_rl;
  378. m.f.f_ma.cl = sa_cl;
  379. strcpy(m.f.f_ma.mask, g->maskname);
  380. insertNode(l, m);
  381. }
  382. }
  383. }
  384. return NORMAL;
  385. }
  386. else if (strcmp(token, "SYSTEMATICCONTIGUOUS") == 0) {
  387. g->dist = 0;
  388. g->add_row = g->rl;
  389. g->add_col = g->cl;
  390. return GEN;
  391. }
  392. else if (strcmp(token, "SYSTEMATICNONCONTIGUOUS") == 0) {
  393. int dist;
  394. dist = atoi(strtok(NULL, "\n"));
  395. g->dist = dist;
  396. g->add_row = g->rl + dist;
  397. g->add_col = g->cl + dist;
  398. g->x = g->sf_x + dist;
  399. g->y = g->sf_y + dist;
  400. return GEN;
  401. }
  402. else if (strcmp(token, "STRATIFIEDRANDOM") == 0) {
  403. int r_strat, c_strat, r_strat_len, c_strat_len, loop, i;
  404. r_strat = atoi(strtok(NULL, "|"));
  405. c_strat = atoi(strtok(NULL, "\n"));
  406. r_strat_len = (int)rint(g->rows / r_strat);
  407. c_strat_len = (int)rint(g->cols / c_strat);
  408. if (r_strat_len < g->rl || c_strat_len < g->cl)
  409. G_fatal_error(_("Too many strats for raster map"));
  410. loop = r_strat * c_strat;
  411. srandom(0);
  412. for (i = 0; i < loop; i++) {
  413. msg m;
  414. if (g->maskname == NULL) {
  415. m.type = AREA;
  416. m.f.f_a.aid = i;
  417. m.f.f_a.x = (int)g->sf_x + ((i % c_strat) * c_strat_len) +
  418. (random() % (c_strat_len - g->cl));
  419. m.f.f_a.y = (int)g->sf_y + (rint(i / c_strat) * r_strat_len) +
  420. (random() % (r_strat_len - g->rl));
  421. m.f.f_a.rl = g->rl;
  422. m.f.f_a.cl = g->cl;
  423. insertNode(l, m);
  424. }
  425. else {
  426. m.type = MASKEDAREA;
  427. m.f.f_ma.aid = i;
  428. m.f.f_ma.x = (int)g->sf_x + ((i % c_strat) * c_strat_len) +
  429. (random() % (c_strat_len - g->cl));
  430. m.f.f_ma.y =
  431. (int)g->sf_y + (rint(i / c_strat) * r_strat_len) +
  432. (random() % (r_strat_len - g->rl));
  433. m.f.f_ma.rl = g->rl;
  434. m.f.f_ma.cl = g->cl;
  435. strcpy(m.f.f_ma.mask, g->maskname);
  436. insertNode(l, m);
  437. }
  438. }
  439. return NORMAL;
  440. }
  441. else {
  442. G_fatal_error(_("Illegal areas disposition"));
  443. return NORMAL;
  444. }
  445. return ERROR;
  446. }
  447. int next_Area(int parsed, struct list *l, struct g_area *g, msg * m)
  448. {
  449. if (parsed == NORMAL) {
  450. if (l->size == 0)
  451. return 0;
  452. else {
  453. msg tmp;
  454. memcpy(&tmp, l->head->m, sizeof(msg));
  455. *m = tmp;
  456. removeNode(l);
  457. return 1;
  458. }
  459. }
  460. else {
  461. return next(g, m);
  462. }
  463. }
  464. int print_Output(int out, msg m)
  465. {
  466. if (m.type != DONE)
  467. return 0;
  468. else {
  469. char s[100];
  470. int len;
  471. sprintf(s, "RESULT %i|%f\n", m.f.f_d.aid, m.f.f_d.res);
  472. len = strlen(s);
  473. if (write(out, s, len) == len)
  474. return 1;
  475. else
  476. return 0;
  477. }
  478. }
  479. int error_Output(int out, msg m)
  480. {
  481. if (m.type != ERROR)
  482. return 0;
  483. else {
  484. char s[100];
  485. sprintf(s, "ERROR %i", m.f.f_d.aid);
  486. if (write(out, s, strlen(s)) == strlen(s))
  487. return 1;
  488. else
  489. return 0;
  490. }
  491. }
  492. int raster_Output(int fd, int aid, struct g_area *g, double res)
  493. {
  494. double toPut = res;
  495. off_t offset = (off_t) aid * sizeof(double);
  496. if (lseek(fd, offset, SEEK_SET) != offset) {
  497. G_message(_("Cannot make lseek"));
  498. return -1;
  499. }
  500. if (write(fd, &toPut, sizeof(double)) == 0)
  501. return 1;
  502. else
  503. return 0;
  504. }
  505. int write_raster(int mv_fd, int random_access, struct g_area *g)
  506. {
  507. int i = 0, j = 0, letti = 0;
  508. double *file_buf;
  509. DCELL *cell_buf;
  510. int cols, rows, center;
  511. cols = g->cols;
  512. rows = g->rows;
  513. center = g->sf_x + ((int)g->cl / 2);
  514. file_buf = G_malloc(cols * sizeof(double));
  515. lseek(random_access, 0, SEEK_SET);
  516. cell_buf = Rast_allocate_d_buf();
  517. Rast_set_d_null_value(cell_buf, Rast_window_cols() + 1);
  518. for (i = 0; i < g->sf_y + ((int)g->rl / 2); i++) {
  519. Rast_put_row(mv_fd, cell_buf, DCELL_TYPE);
  520. }
  521. for (i = 0; i < rows; i++) {
  522. letti = read(random_access, file_buf, (cols * sizeof(double)));
  523. if (letti == -1)
  524. G_message("%s", strerror(errno));
  525. for (j = 0; j < cols; j++) {
  526. cell_buf[j + center] = file_buf[j];
  527. }
  528. Rast_put_row(mv_fd, cell_buf, DCELL_TYPE);
  529. }
  530. Rast_set_d_null_value(cell_buf, Rast_window_cols() + 1);
  531. for (i = 0; i < Rast_window_rows() - g->sf_y - g->rows; i++)
  532. Rast_put_row(mv_fd, cell_buf, DCELL_TYPE);
  533. return 1;
  534. }