n_les_assemble.c 41 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398
  1. /*****************************************************************************
  2. *
  3. * MODULE: Grass PDE Numerical Library
  4. * AUTHOR(S): Soeren Gebbert, Berlin (GER) Dec 2006
  5. * soerengebbert <at> gmx <dot> de
  6. *
  7. * PURPOSE: functions to assemble a linear equation system
  8. * part of the gpde library
  9. *
  10. * COPYRIGHT: (C) 2000 by the GRASS Development Team
  11. *
  12. * This program is free software under the GNU General Public
  13. * License (>=v2). Read the file COPYING that comes with GRASS
  14. * for details.
  15. *
  16. *****************************************************************************/
  17. #include <math.h>
  18. #include <grass/N_pde.h>
  19. /* local protos */
  20. static int make_les_entry_2d(int i, int j, int offset_i, int offset_j,
  21. int count, int pos, N_les * les,
  22. G_math_spvector * spvect,
  23. N_array_2d * cell_count, N_array_2d * status,
  24. N_array_2d * start_val, double entry,
  25. int cell_type);
  26. static int make_les_entry_3d(int i, int j, int k, int offset_i, int offset_j,
  27. int offset_k, int count, int pos, N_les * les,
  28. G_math_spvector * spvect,
  29. N_array_3d * cell_count, N_array_3d * status,
  30. N_array_3d * start_val, double entry,
  31. int cell_type);
  32. /* *************************************************************** *
  33. * ********************** N_alloc_5star ************************** *
  34. * *************************************************************** */
  35. /*!
  36. * \brief allocate a 5 point star data structure
  37. *
  38. * \return N_data_star *
  39. * */
  40. N_data_star *N_alloc_5star(void)
  41. {
  42. N_data_star *star = (N_data_star *) G_calloc(1, sizeof(N_data_star));
  43. star->type = N_5_POINT_STAR;
  44. star->count = 5;
  45. return star;
  46. }
  47. /* *************************************************************** *
  48. * ********************* N_alloc_7star *************************** *
  49. * *************************************************************** */
  50. /*!
  51. * \brief allocate a 7 point star data structure
  52. *
  53. * \return N_data_star *
  54. * */
  55. N_data_star *N_alloc_7star(void)
  56. {
  57. N_data_star *star = (N_data_star *) G_calloc(1, sizeof(N_data_star));
  58. star->type = N_7_POINT_STAR;
  59. star->count = 7;
  60. return star;
  61. }
  62. /* *************************************************************** *
  63. * ********************* N_alloc_9star *************************** *
  64. * *************************************************************** */
  65. /*!
  66. * \brief allocate a 9 point star data structure
  67. *
  68. * \return N_data_star *
  69. *
  70. * \attention The 9 point start is not yet implemented in the matrix assembling function
  71. *
  72. * */
  73. N_data_star *N_alloc_9star(void)
  74. {
  75. N_data_star *star = (N_data_star *) G_calloc(1, sizeof(N_data_star));
  76. star->type = N_9_POINT_STAR;
  77. star->count = 9;
  78. return star;
  79. }
  80. /* *************************************************************** *
  81. * ********************* N_alloc_27star ************************** *
  82. * *************************************************************** */
  83. /*!
  84. * \brief allocate a 27 point star data structure
  85. *
  86. * \return N_data_star *
  87. *
  88. * \attention The 27 point start is not yet implemented in the matrix assembling function
  89. *
  90. * */
  91. N_data_star *N_alloc_27star(void)
  92. {
  93. N_data_star *star = (N_data_star *) G_calloc(1, sizeof(N_data_star));
  94. star->type = N_27_POINT_STAR;
  95. star->count = 27;
  96. return star;
  97. }
  98. /* *************************************************************** *
  99. * ********************** N_create_5star ************************* *
  100. * *************************************************************** */
  101. /*!
  102. * \brief allocate and initialize a 5 point star data structure
  103. *
  104. * \param C double
  105. * \param W double
  106. * \param E double
  107. * \param N double
  108. * \param S double
  109. * \param V double
  110. * \return N_data_star *
  111. * */
  112. N_data_star *N_create_5star(double C, double W, double E, double N,
  113. double S, double V)
  114. {
  115. N_data_star *star = N_alloc_5star();
  116. star->C = C;
  117. star->W = W;
  118. star->E = E;
  119. star->N = N;
  120. star->S = S;
  121. star->V = V;
  122. G_debug(5, "N_create_5star: w %g e %g n %g s %g c %g v %g\n", star->W,
  123. star->E, star->N, star->S, star->C, star->V);
  124. return star;
  125. }
  126. /* *************************************************************** *
  127. * ************************* N_create_7star ********************** *
  128. * *************************************************************** */
  129. /*!
  130. * \brief allocate and initialize a 7 point star data structure
  131. *
  132. * \param C double
  133. * \param W double
  134. * \param E double
  135. * \param N double
  136. * \param S double
  137. * \param T double
  138. * \param B double
  139. * \param V double
  140. * \return N_data_star *
  141. * */
  142. N_data_star *N_create_7star(double C, double W, double E, double N,
  143. double S, double T, double B, double V)
  144. {
  145. N_data_star *star = N_alloc_7star();
  146. star->C = C;
  147. star->W = W;
  148. star->E = E;
  149. star->N = N;
  150. star->S = S;
  151. star->T = T;
  152. star->B = B;
  153. star->V = V;
  154. G_debug(5, "N_create_7star: w %g e %g n %g s %g t %g b %g c %g v %g\n",
  155. star->W, star->E, star->N, star->S, star->T, star->B, star->C,
  156. star->V);
  157. return star;
  158. }
  159. /* *************************************************************** *
  160. * ************************ N_create_9star *********************** *
  161. * *************************************************************** */
  162. /*!
  163. * \brief allocate and initialize a 9 point star data structure
  164. *
  165. * \param C double
  166. * \param W double
  167. * \param E double
  168. * \param N double
  169. * \param S double
  170. * \param NW double
  171. * \param SW double
  172. * \param NE double
  173. * \param SE double
  174. * \param V double
  175. * \return N_data_star *
  176. * */
  177. N_data_star *N_create_9star(double C, double W, double E, double N,
  178. double S, double NW, double SW, double NE,
  179. double SE, double V)
  180. {
  181. N_data_star *star = N_alloc_9star();
  182. star->C = C;
  183. star->W = W;
  184. star->E = E;
  185. star->N = N;
  186. star->S = S;
  187. star->NW = NW;
  188. star->SW = SW;
  189. star->NE = NE;
  190. star->SE = SE;
  191. star->V = V;
  192. G_debug(5,
  193. "N_create_9star: w %g e %g n %g s %g nw %g sw %g ne %g se %g c %g v %g\n",
  194. star->W, star->E, star->N, star->S, star->NW, star->SW, star->NE,
  195. star->SE, star->C, star->V);
  196. return star;
  197. }
  198. /* *************************************************************** *
  199. * ************************ N_create_27star *********************** *
  200. * *************************************************************** */
  201. /*!
  202. * \brief allocate and initialize a 27 point star data structure
  203. *
  204. * \param C double
  205. * \param W double
  206. * \param E double
  207. * \param N double
  208. * \param S double
  209. * \param NW double
  210. * \param SW double
  211. * \param NE double
  212. * \param SE double
  213. * \param T double
  214. * \param W_T double
  215. * \param E_T double
  216. * \param N_T double
  217. * \param S_T double
  218. * \param NW_T double
  219. * \param SW_T double
  220. * \param NE_T double
  221. * \param SE_T double
  222. * \param B double
  223. * \param W_B double
  224. * \param E_B double
  225. * \param N_B double
  226. * \param S_B double
  227. * \param NW_B double
  228. * \param SW_B double
  229. * \param NE_B double
  230. * \param SE_B double
  231. * \param V double
  232. * \return N_data_star *
  233. * */
  234. N_data_star *N_create_27star(double C, double W, double E, double N, double S,
  235. double NW, double SW, double NE, double SE,
  236. double T, double W_T, double E_T, double N_T,
  237. double S_T, double NW_T, double SW_T,
  238. double NE_T, double SE_T, double B, double W_B,
  239. double E_B, double N_B, double S_B, double NW_B,
  240. double SW_B, double NE_B, double SE_B, double V)
  241. {
  242. N_data_star *star = N_alloc_27star();
  243. star->C = C;
  244. star->W = W;
  245. star->E = E;
  246. star->N = N;
  247. star->S = S;
  248. star->NW = NW;
  249. star->SW = SW;
  250. star->NE = NE;
  251. star->SE = SE;
  252. star->T = T;
  253. star->W_T = W_T;
  254. star->E_T = E_T;
  255. star->N_T = N_T;
  256. star->S_T = S_T;
  257. star->NW_T = NW_T;
  258. star->SW_T = SW_T;
  259. star->NE_T = NE_T;
  260. star->SE_T = SE_T;
  261. star->B = B;
  262. star->W_B = W_B;
  263. star->E_B = E_B;
  264. star->N_B = N_B;
  265. star->S_B = S_B;
  266. star->NW_B = NW_B;
  267. star->SW_B = SW_B;
  268. star->NE_B = NE_B;
  269. star->SE_B = SE_B;
  270. star->V = V;
  271. G_debug(5,
  272. "N_create_27star: w %g e %g n %g s %g nw %g sw %g ne %g se %g c %g v %g\n",
  273. star->W, star->E, star->N, star->S, star->NW, star->SW, star->NE,
  274. star->SE, star->C, star->V);
  275. G_debug(5,
  276. "N_create_27star: w_t %g e_t %g n_t %g s_t %g nw_t %g sw_t %g ne_t %g se_t %g t %g \n",
  277. star->W_T, star->E_T, star->N_T, star->S_T, star->NW_T,
  278. star->SW_T, star->NE_T, star->SE_T, star->T);
  279. G_debug(5,
  280. "N_create_27star: w_b %g e_b %g n_b %g s_b %g nw_b %g sw_b %g ne_b %g se_B %g b %g\n",
  281. star->W_B, star->E_B, star->N_B, star->S_B, star->NW_B,
  282. star->SW_B, star->NE_B, star->SE_B, star->B);
  283. return star;
  284. }
  285. /* *************************************************************** *
  286. * ****************** N_set_les_callback_3d_func ***************** *
  287. * *************************************************************** */
  288. /*!
  289. * \brief Set the callback function which is called while assembling the les in 3d
  290. *
  291. * \param data N_les_callback_3d *
  292. * \param callback_func_3d N_data_star *
  293. * \return void
  294. * */
  295. void
  296. N_set_les_callback_3d_func(N_les_callback_3d * data,
  297. N_data_star * (*callback_func_3d) ())
  298. {
  299. data->callback = callback_func_3d;
  300. }
  301. /* *************************************************************** *
  302. * *************** N_set_les_callback_2d_func ******************** *
  303. * *************************************************************** */
  304. /*!
  305. * \brief Set the callback function which is called while assembling the les in 2d
  306. *
  307. * \param data N_les_callback_2d *
  308. * \param callback_func_2d N_data_star *
  309. * \return void
  310. * */
  311. void
  312. N_set_les_callback_2d_func(N_les_callback_2d * data,
  313. N_data_star * (*callback_func_2d) ())
  314. {
  315. data->callback = callback_func_2d;
  316. }
  317. /* *************************************************************** *
  318. * ************** N_alloc_les_callback_3d ************************ *
  319. * *************************************************************** */
  320. /*!
  321. * \brief Allocate the structure holding the callback function
  322. *
  323. * A template callback is set. Use N_set_les_callback_3d_func
  324. * to set up a specific function.
  325. *
  326. * \return N_les_callback_3d *
  327. * */
  328. N_les_callback_3d *N_alloc_les_callback_3d(void)
  329. {
  330. N_les_callback_3d *call;
  331. call = (N_les_callback_3d *) G_calloc(1, sizeof(N_les_callback_3d *));
  332. call->callback = N_callback_template_3d;
  333. return call;
  334. }
  335. /* *************************************************************** *
  336. * *************** N_alloc_les_callback_2d *********************** *
  337. * *************************************************************** */
  338. /*!
  339. * \brief Allocate the structure holding the callback function
  340. *
  341. * A template callback is set. Use N_set_les_callback_2d_func
  342. * to set up a specific function.
  343. *
  344. * \return N_les_callback_2d *
  345. * */
  346. N_les_callback_2d *N_alloc_les_callback_2d(void)
  347. {
  348. N_les_callback_2d *call;
  349. call = (N_les_callback_2d *) G_calloc(1, sizeof(N_les_callback_2d *));
  350. call->callback = N_callback_template_2d;
  351. return call;
  352. }
  353. /* *************************************************************** *
  354. * ******************** N_callback_template_3d ******************* *
  355. * *************************************************************** */
  356. /*!
  357. * \brief A callback template creates a 7 point star structure
  358. *
  359. * This is a template callback for mass balance calculation with 7 point stars
  360. * based on 3d data (g3d).
  361. *
  362. * \param data void *
  363. * \param geom N_geom_data *
  364. * \param depth int
  365. * \param row int
  366. * \param col int
  367. * \return N_data_star *
  368. *
  369. * */
  370. N_data_star *N_callback_template_3d(void *data, N_geom_data * geom, int col,
  371. int row, int depth)
  372. {
  373. N_data_star *star = N_alloc_7star();
  374. star->E = 1 / geom->dx;
  375. star->W = 1 / geom->dx;
  376. star->N = 1 / geom->dy;
  377. star->S = 1 / geom->dy;
  378. star->T = 1 / geom->dz;
  379. star->B = 1 / geom->dz;
  380. star->C = -1 * (2 / geom->dx + 2 / geom->dy + 2 / geom->dz);
  381. star->V = -1;
  382. G_debug(5,
  383. "N_callback_template_3d: w %g e %g n %g s %g t %g b %g c %g v %g\n",
  384. star->W, star->E, star->N, star->S, star->T, star->B, star->C,
  385. star->V);
  386. return star;
  387. }
  388. /* *************************************************************** *
  389. * ********************* N_callback_template_2d ****************** *
  390. * *************************************************************** */
  391. /*!
  392. * \brief A callback template creates a 9 point star structure
  393. *
  394. * This is a template callback for mass balance calculation with 9 point stars
  395. * based on 2d data (raster).
  396. *
  397. * \param data void *
  398. * \param geom N_geom_data *
  399. * \param row int
  400. * \param col int
  401. * \return N_data_star *
  402. *
  403. * */
  404. N_data_star *N_callback_template_2d(void *data, N_geom_data * geom, int col,
  405. int row)
  406. {
  407. N_data_star *star = N_alloc_9star();
  408. star->E = 1 / geom->dx;
  409. star->NE = 1 / sqrt(geom->dx * geom->dx + geom->dy * geom->dy);
  410. star->SE = 1 / sqrt(geom->dx * geom->dx + geom->dy * geom->dy);
  411. star->W = 1 / geom->dx;
  412. star->NW = 1 / sqrt(geom->dx * geom->dx + geom->dy * geom->dy);
  413. star->SW = 1 / sqrt(geom->dx * geom->dx + geom->dy * geom->dy);
  414. star->N = 1 / geom->dy;
  415. star->S = 1 / geom->dy;
  416. star->C =
  417. -1 * (star->E + star->NE + star->SE + star->W + star->NW + star->SW +
  418. star->N + star->S);
  419. star->V = 0;
  420. return star;
  421. }
  422. /* *************************************************************** *
  423. * ******************** N_assemble_les_2d ************************ *
  424. * *************************************************************** */
  425. /*!
  426. * \brief Assemble a linear equation system (les) based on 2d location data (raster) and active cells
  427. *
  428. * This function calls #N_assemble_les_2d_param
  429. *
  430. */
  431. N_les *N_assemble_les_2d(int les_type, N_geom_data * geom,
  432. N_array_2d * status, N_array_2d * start_val,
  433. void *data, N_les_callback_2d * call)
  434. {
  435. return N_assemble_les_2d_param(les_type, geom, status, start_val, data,
  436. call, N_CELL_ACTIVE);
  437. }
  438. /*!
  439. * \brief Assemble a linear equation system (les) based on 2d location data (raster) and active cells
  440. *
  441. * This function calls #N_assemble_les_2d_param
  442. *
  443. */
  444. N_les *N_assemble_les_2d_active(int les_type, N_geom_data * geom,
  445. N_array_2d * status, N_array_2d * start_val,
  446. void *data, N_les_callback_2d * call)
  447. {
  448. return N_assemble_les_2d_param(les_type, geom, status, start_val, data,
  449. call, N_CELL_ACTIVE);
  450. }
  451. /*!
  452. * \brief Assemble a linear equation system (les) based on 2d location data (raster) and active and dirichlet cells
  453. *
  454. * This function calls #N_assemble_les_2d_param
  455. *
  456. */
  457. N_les *N_assemble_les_2d_dirichlet(int les_type, N_geom_data * geom,
  458. N_array_2d * status,
  459. N_array_2d * start_val, void *data,
  460. N_les_callback_2d * call)
  461. {
  462. return N_assemble_les_2d_param(les_type, geom, status, start_val, data,
  463. call, N_CELL_DIRICHLET);
  464. }
  465. /*!
  466. * \brief Assemble a linear equation system (les) based on 2d location data (raster)
  467. *
  468. *
  469. * The linear equation system type can be set to N_NORMAL_LES to create a regular
  470. * matrix, or to N_SPARSE_LES to create a sparse matrix. This function returns
  471. * a new created linear equation system which can be solved with
  472. * linear equation solvers. An 2d array with start values and an 2d status array
  473. * must be provided as well as the location geometry and a void pointer to data
  474. * passed to the callback which creates the les row entries. This callback
  475. * must be defined in the N_les_callback_2d strcuture.
  476. *
  477. * The creation of the les is parallelized with OpenMP.
  478. * If you implement new callbacks, please make sure that the
  479. * function calls are thread safe.
  480. *
  481. *
  482. * the les can be created in two ways, with dirichlet and similar cells and without them,
  483. * to spare some memory. If the les is created with dirichlet cell, the dirichlet boundary condition
  484. * must be added.
  485. *
  486. * \param les_type int
  487. * \param geom N_geom_data*
  488. * \param status N_array_2d *
  489. * \param start_val N_array_2d *
  490. * \param data void *
  491. * \param cell_type int -- les assemble based on N_CELL_ACTIVE or N_CELL_DIRICHLET
  492. * \param call N_les_callback_2d *
  493. * \return N_les *
  494. * */
  495. N_les *N_assemble_les_2d_param(int les_type, N_geom_data * geom,
  496. N_array_2d * status, N_array_2d * start_val,
  497. void *data, N_les_callback_2d * call,
  498. int cell_type)
  499. {
  500. int i, j, count = 0, pos = 0;
  501. int cell_type_count = 0;
  502. int **index_ij;
  503. N_array_2d *cell_count;
  504. N_les *les = NULL;
  505. G_debug(2,
  506. "N_assemble_les_2d: starting to assemble the linear equation system");
  507. /* At first count the number of valid cells and save
  508. * each number in a new 2d array. Those numbers are used
  509. * to create the linear equation system.
  510. * */
  511. cell_count = N_alloc_array_2d(geom->cols, geom->rows, 1, CELL_TYPE);
  512. /* include dirichlet cells in the les */
  513. if (cell_type == N_CELL_DIRICHLET) {
  514. for (j = 0; j < geom->rows; j++) {
  515. for (i = 0; i < geom->cols; i++) {
  516. /*use all non-inactive cells for les creation */
  517. if (N_CELL_INACTIVE < N_get_array_2d_c_value(status, i, j) &&
  518. N_get_array_2d_c_value(status, i, j) < N_MAX_CELL_STATE)
  519. cell_type_count++;
  520. }
  521. }
  522. }
  523. /*use only active cell in the les */
  524. if (cell_type == N_CELL_ACTIVE) {
  525. for (j = 0; j < geom->rows; j++) {
  526. for (i = 0; i < geom->cols; i++) {
  527. /*count only active cells */
  528. if (N_CELL_ACTIVE == N_get_array_2d_d_value(status, i, j))
  529. cell_type_count++;
  530. }
  531. }
  532. }
  533. G_debug(2, "N_assemble_les_2d: number of used cells %i\n",
  534. cell_type_count);
  535. if (cell_type_count == 0)
  536. G_fatal_error
  537. ("Not enough cells [%i] to create the linear equation system. Check the cell status. Only active cells (value = 1) are used to create the equation system.",
  538. cell_type_count);
  539. /* Then allocate the memory for the linear equation system (les).
  540. * Only valid cells are used to create the les. */
  541. index_ij = (int **)G_calloc(cell_type_count, sizeof(int *));
  542. for (i = 0; i < cell_type_count; i++)
  543. index_ij[i] = (int *)G_calloc(2, sizeof(int));
  544. les = N_alloc_les_Ax_b(cell_type_count, les_type);
  545. count = 0;
  546. /*count the number of cells which should be used to create the linear equation system */
  547. /*save the i and j indices and create a ordered numbering */
  548. for (j = 0; j < geom->rows; j++) {
  549. for (i = 0; i < geom->cols; i++) {
  550. /*count every non-inactive cell */
  551. if (cell_type == N_CELL_DIRICHLET) {
  552. if (N_CELL_INACTIVE < N_get_array_2d_c_value(status, i, j) &&
  553. N_get_array_2d_c_value(status, i, j) < N_MAX_CELL_STATE) {
  554. N_put_array_2d_c_value(cell_count, i, j, count);
  555. index_ij[count][0] = i;
  556. index_ij[count][1] = j;
  557. count++;
  558. G_debug(5,
  559. "N_assemble_les_2d: non-inactive cells count %i at pos x[%i] y[%i]\n",
  560. count, i, j);
  561. }
  562. /*count every active cell */
  563. }
  564. else if (N_CELL_ACTIVE == N_get_array_2d_c_value(status, i, j)) {
  565. N_put_array_2d_c_value(cell_count, i, j, count);
  566. index_ij[count][0] = i;
  567. index_ij[count][1] = j;
  568. count++;
  569. G_debug(5,
  570. "N_assemble_les_2d: active cells count %i at pos x[%i] y[%i]\n",
  571. count, i, j);
  572. }
  573. }
  574. }
  575. G_debug(2, "N_assemble_les_2d: starting the parallel assemble loop");
  576. /* Assemble the matrix in parallel */
  577. #pragma omp parallel for private(i, j, pos, count) schedule(static)
  578. for (count = 0; count < cell_type_count; count++) {
  579. i = index_ij[count][0];
  580. j = index_ij[count][1];
  581. /*create the entries for the */
  582. N_data_star *items = call->callback(data, geom, i, j);
  583. /* we need a sparse vector pointer anytime */
  584. G_math_spvector *spvect = NULL;
  585. /*allocate a sprase vector */
  586. if (les_type == N_SPARSE_LES) {
  587. spvect = G_math_alloc_spvector(items->count);
  588. }
  589. /* initial conditions */
  590. les->x[count] = N_get_array_2d_d_value(start_val, i, j);
  591. /* the entry in the vector b */
  592. les->b[count] = items->V;
  593. /* pos describes the position in the sparse vector.
  594. * the first entry is always the diagonal entry of the matrix*/
  595. pos = 0;
  596. if (les_type == N_SPARSE_LES) {
  597. spvect->index[pos] = count;
  598. spvect->values[pos] = items->C;
  599. }
  600. else {
  601. les->A[count][count] = items->C;
  602. }
  603. /* western neighbour, entry is col - 1 */
  604. if (i > 0) {
  605. pos = make_les_entry_2d(i, j, -1, 0, count, pos, les, spvect,
  606. cell_count, status, start_val, items->W,
  607. cell_type);
  608. }
  609. /* eastern neighbour, entry col + 1 */
  610. if (i < geom->cols - 1) {
  611. pos = make_les_entry_2d(i, j, 1, 0, count, pos, les, spvect,
  612. cell_count, status, start_val, items->E,
  613. cell_type);
  614. }
  615. /* northern neighbour, entry row - 1 */
  616. if (j > 0) {
  617. pos =
  618. make_les_entry_2d(i, j, 0, -1, count, pos, les, spvect,
  619. cell_count, status, start_val, items->N,
  620. cell_type);
  621. }
  622. /* southern neighbour, entry row + 1 */
  623. if (j < geom->rows - 1) {
  624. pos = make_les_entry_2d(i, j, 0, 1, count, pos, les, spvect,
  625. cell_count, status, start_val, items->S,
  626. cell_type);
  627. }
  628. /*in case of a nine point star, we have additional entries */
  629. if (items->type == N_9_POINT_STAR) {
  630. /* north-western neighbour, entry is col - 1 row - 1 */
  631. if (i > 0 && j > 0) {
  632. pos = make_les_entry_2d(i, j, -1, -1, count, pos, les, spvect,
  633. cell_count, status, start_val,
  634. items->NW, cell_type);
  635. }
  636. /* north-eastern neighbour, entry col + 1 row - 1 */
  637. if (i < geom->cols - 1 && j > 0) {
  638. pos = make_les_entry_2d(i, j, 1, -1, count, pos, les, spvect,
  639. cell_count, status, start_val,
  640. items->NE, cell_type);
  641. }
  642. /* south-western neighbour, entry is col - 1 row + 1 */
  643. if (i > 0 && j < geom->rows - 1) {
  644. pos = make_les_entry_2d(i, j, -1, 1, count, pos, les, spvect,
  645. cell_count, status, start_val,
  646. items->SW, cell_type);
  647. }
  648. /* south-eastern neighbour, entry col + 1 row + 1 */
  649. if (i < geom->cols - 1 && j < geom->rows - 1) {
  650. pos = make_les_entry_2d(i, j, 1, 1, count, pos, les, spvect,
  651. cell_count, status, start_val,
  652. items->SE, cell_type);
  653. }
  654. }
  655. /*How many entries in the les */
  656. if (les->type == N_SPARSE_LES) {
  657. spvect->cols = pos + 1;
  658. G_math_add_spvector(les->Asp, spvect, count);
  659. }
  660. if (items)
  661. G_free(items);
  662. }
  663. /*release memory */
  664. N_free_array_2d(cell_count);
  665. for (i = 0; i < cell_type_count; i++)
  666. G_free(index_ij[i]);
  667. G_free(index_ij);
  668. return les;
  669. }
  670. /*!
  671. * \brief Integrate Dirichlet or Transmission boundary conditions into the les (2s)
  672. *
  673. * Dirichlet and Transmission boundary conditions will be integrated into
  674. * the provided linear equation system. This is meaningfull if
  675. * the les was created with #N_assemble_les_2d_dirichlet, because in
  676. * this case Dirichlet boundary conditions are not automatically included.
  677. *
  678. * The provided les will be modified:
  679. *
  680. * Ax = b will be split into Ax_u + Ax_d = b
  681. *
  682. * x_u - the unknowns
  683. * x_d - the Dirichlet cells
  684. *
  685. * Ax_u = b -Ax_d will be computed. Then the matrix A will be modified to
  686. *
  687. * | A_u 0 | x_u
  688. * | 0 I | x_d
  689. *
  690. * \param les N_les* -- the linear equation system
  691. * \param geom N_geom_data* -- geometrical data information
  692. * \param status N_array_2d* -- the status array containing the cell types
  693. * \param start_val N_array_2d* -- an array with start values
  694. * \return int -- 1 = success, 0 = failure
  695. * */
  696. int N_les_integrate_dirichlet_2d(N_les * les, N_geom_data * geom,
  697. N_array_2d * status, N_array_2d * start_val)
  698. {
  699. int rows, cols;
  700. int count = 0;
  701. int i, j, x, y, stat;
  702. double *dvect1;
  703. double *dvect2;
  704. G_debug(2,
  705. "N_les_integrate_dirichlet_2d: integrating the dirichlet boundary condition");
  706. rows = geom->rows;
  707. cols = geom->cols;
  708. /*we nned to additional vectors */
  709. dvect1 = (double *)G_calloc(les->cols, sizeof(double));
  710. dvect2 = (double *)G_calloc(les->cols, sizeof(double));
  711. /*fill the first one with the x vector data of Dirichlet cells */
  712. count = 0;
  713. for (y = 0; y < rows; y++) {
  714. for (x = 0; x < cols; x++) {
  715. stat = N_get_array_2d_c_value(status, x, y);
  716. if (stat > N_CELL_ACTIVE && stat < N_MAX_CELL_STATE) {
  717. dvect1[count] = N_get_array_2d_d_value(start_val, x, y);
  718. count++;
  719. }
  720. else if (stat == N_CELL_ACTIVE) {
  721. dvect1[count] = 0.0;
  722. count++;
  723. }
  724. }
  725. }
  726. #pragma omp parallel default(shared)
  727. {
  728. /*perform the matrix vector product and */
  729. if (les->type == N_SPARSE_LES)
  730. G_math_Ax_sparse(les->Asp, dvect1, dvect2, les->rows);
  731. else
  732. G_math_d_Ax(les->A, dvect1, dvect2, les->rows, les->cols);
  733. #pragma omp for schedule (static) private(i)
  734. for (i = 0; i < les->cols; i++)
  735. les->b[i] = les->b[i] - dvect2[i];
  736. }
  737. /*now set the Dirichlet cell rows and cols to zero and the
  738. * diagonal entry to 1*/
  739. count = 0;
  740. for (y = 0; y < rows; y++) {
  741. for (x = 0; x < cols; x++) {
  742. stat = N_get_array_2d_c_value(status, x, y);
  743. if (stat > N_CELL_ACTIVE && stat < N_MAX_CELL_STATE) {
  744. if (les->type == N_SPARSE_LES) {
  745. /*set the rows to zero */
  746. for (i = 0; i < les->Asp[count]->cols; i++)
  747. les->Asp[count]->values[i] = 0.0;
  748. /*set the cols to zero */
  749. for (i = 0; i < les->rows; i++) {
  750. for (j = 0; j < les->Asp[i]->cols; j++) {
  751. if (les->Asp[i]->index[j] == count)
  752. les->Asp[i]->values[j] = 0.0;
  753. }
  754. }
  755. /*entry on the diagonal */
  756. les->Asp[count]->values[0] = 1.0;
  757. }
  758. else {
  759. /*set the rows to zero */
  760. for (i = 0; i < les->cols; i++)
  761. les->A[count][i] = 0.0;
  762. /*set the cols to zero */
  763. for (i = 0; i < les->rows; i++)
  764. les->A[i][count] = 0.0;
  765. /*entry on the diagonal */
  766. les->A[count][count] = 1.0;
  767. }
  768. }
  769. if (stat >= N_CELL_ACTIVE)
  770. count++;
  771. }
  772. }
  773. return 0;
  774. }
  775. /* **************************************************************** */
  776. /* **** make an entry in the les (2d) ***************************** */
  777. /* **************************************************************** */
  778. int make_les_entry_2d(int i, int j, int offset_i, int offset_j, int count,
  779. int pos, N_les * les, G_math_spvector * spvect,
  780. N_array_2d * cell_count, N_array_2d * status,
  781. N_array_2d * start_val, double entry, int cell_type)
  782. {
  783. int K;
  784. int di = offset_i;
  785. int dj = offset_j;
  786. K = N_get_array_2d_c_value(cell_count, i + di, j + dj) -
  787. N_get_array_2d_c_value(cell_count, i, j);
  788. /* active cells build the linear equation system */
  789. if (cell_type == N_CELL_ACTIVE) {
  790. /* dirichlet or transmission cells must be handled like this */
  791. if (N_get_array_2d_c_value(status, i + di, j + dj) > N_CELL_ACTIVE &&
  792. N_get_array_2d_c_value(status, i + di, j + dj) < N_MAX_CELL_STATE)
  793. les->b[count] -=
  794. N_get_array_2d_d_value(start_val, i + di, j + dj) * entry;
  795. else if (N_get_array_2d_c_value(status, i + di, j + dj) ==
  796. N_CELL_ACTIVE) {
  797. if ((count + K) >= 0 && (count + K) < les->cols) {
  798. G_debug(5,
  799. " make_les_entry_2d: (N_CELL_ACTIVE) create matrix entry at row[%i] col[%i] value %g\n",
  800. count, count + K, entry);
  801. pos++;
  802. if (les->type == N_SPARSE_LES) {
  803. spvect->index[pos] = count + K;
  804. spvect->values[pos] = entry;
  805. }
  806. else {
  807. les->A[count][count + K] = entry;
  808. }
  809. }
  810. }
  811. } /* if dirichlet cells should be used then check for all valid cell neighbours */
  812. else if (cell_type == N_CELL_DIRICHLET) {
  813. /* all valid cells */
  814. if (N_get_array_2d_c_value(status, i + di, j + dj) > N_CELL_INACTIVE
  815. && N_get_array_2d_c_value(status, i + di,
  816. j + dj) < N_MAX_CELL_STATE) {
  817. if ((count + K) >= 0 && (count + K) < les->cols) {
  818. G_debug(5,
  819. " make_les_entry_2d: (N_CELL_DIRICHLET) create matrix entry at row[%i] col[%i] value %g\n",
  820. count, count + K, entry);
  821. pos++;
  822. if (les->type == N_SPARSE_LES) {
  823. spvect->index[pos] = count + K;
  824. spvect->values[pos] = entry;
  825. }
  826. else {
  827. les->A[count][count + K] = entry;
  828. }
  829. }
  830. }
  831. }
  832. return pos;
  833. }
  834. /* *************************************************************** *
  835. * ******************** N_assemble_les_3d ************************ *
  836. * *************************************************************** */
  837. /*!
  838. * \brief Assemble a linear equation system (les) based on 3d location data (g3d) active cells
  839. *
  840. * This function calls #N_assemble_les_3d_param
  841. * */
  842. N_les *N_assemble_les_3d(int les_type, N_geom_data * geom,
  843. N_array_3d * status, N_array_3d * start_val,
  844. void *data, N_les_callback_3d * call)
  845. {
  846. return N_assemble_les_3d_param(les_type, geom, status, start_val, data,
  847. call, N_CELL_ACTIVE);
  848. }
  849. /*!
  850. * \brief Assemble a linear equation system (les) based on 3d location data (g3d) active cells
  851. *
  852. * This function calls #N_assemble_les_3d_param
  853. * */
  854. N_les *N_assemble_les_3d_active(int les_type, N_geom_data * geom,
  855. N_array_3d * status, N_array_3d * start_val,
  856. void *data, N_les_callback_3d * call)
  857. {
  858. return N_assemble_les_3d_param(les_type, geom, status, start_val, data,
  859. call, N_CELL_ACTIVE);
  860. }
  861. /*!
  862. * \brief Assemble a linear equation system (les) based on 3d location data (g3d) active and dirichlet cells
  863. *
  864. * This function calls #N_assemble_les_3d_param
  865. * */
  866. N_les *N_assemble_les_3d_dirichlet(int les_type, N_geom_data * geom,
  867. N_array_3d * status,
  868. N_array_3d * start_val, void *data,
  869. N_les_callback_3d * call)
  870. {
  871. return N_assemble_les_3d_param(les_type, geom, status, start_val, data,
  872. call, N_CELL_DIRICHLET);
  873. }
  874. /*!
  875. * \brief Assemble a linear equation system (les) based on 3d location data (g3d)
  876. *
  877. * The linear equation system type can be set to N_NORMAL_LES to create a regular
  878. * matrix, or to N_SPARSE_LES to create a sparse matrix. This function returns
  879. * a new created linear equation system which can be solved with
  880. * linear equation solvers. An 3d array with start values and an 3d status array
  881. * must be provided as well as the location geometry and a void pointer to data
  882. * passed to the callback which creates the les row entries. This callback
  883. * must be defined in the N_les_callback_3d structure.
  884. *
  885. * The creation of the les is parallelized with OpenMP.
  886. * If you implement new callbacks, please make sure that the
  887. * function calls are thread safe.
  888. *
  889. * the les can be created in two ways, with dirichlet and similar cells and without them,
  890. * to spare some memory. If the les is created with dirichlet cell, the dirichlet boundary condition
  891. * must be added.
  892. *
  893. * \param les_type int
  894. * \param geom N_geom_data*
  895. * \param status N_array_3d *
  896. * \param start_val N_array_3d *
  897. * \param data void *
  898. * \param call N_les_callback_3d *
  899. * \param cell_type int -- les assemble based on N_CELL_ACTIVE or N_CELL_DIRICHLET
  900. * \return N_les *
  901. * */
  902. N_les *N_assemble_les_3d_param(int les_type, N_geom_data * geom,
  903. N_array_3d * status, N_array_3d * start_val,
  904. void *data, N_les_callback_3d * call,
  905. int cell_type)
  906. {
  907. int i, j, k, count = 0, pos = 0;
  908. int cell_type_count = 0;
  909. N_array_3d *cell_count;
  910. N_les *les = NULL;
  911. int **index_ij;
  912. G_debug(2,
  913. "N_assemble_les_3d: starting to assemble the linear equation system");
  914. cell_count =
  915. N_alloc_array_3d(geom->cols, geom->rows, geom->depths, 1, DCELL_TYPE);
  916. /* First count the number of valid cells and save
  917. * each number in a new 3d array. Those numbers are used
  918. * to create the linear equation system.*/
  919. if (cell_type == N_CELL_DIRICHLET) {
  920. /* include dirichlet cells in the les */
  921. for (k = 0; k < geom->depths; k++) {
  922. for (j = 0; j < geom->rows; j++) {
  923. for (i = 0; i < geom->cols; i++) {
  924. /*use all non-inactive cells for les creation */
  925. if (N_CELL_INACTIVE <
  926. (int)N_get_array_3d_d_value(status, i, j, k) &&
  927. (int)N_get_array_3d_d_value(status, i, j,
  928. k) < N_MAX_CELL_STATE)
  929. cell_type_count++;
  930. }
  931. }
  932. }
  933. }
  934. else {
  935. /*use only active cell in the les */
  936. for (k = 0; k < geom->depths; k++) {
  937. for (j = 0; j < geom->rows; j++) {
  938. for (i = 0; i < geom->cols; i++) {
  939. /*count only active cells */
  940. if (N_CELL_ACTIVE
  941. == (int)N_get_array_3d_d_value(status, i, j, k))
  942. cell_type_count++;
  943. }
  944. }
  945. }
  946. }
  947. G_debug(2,
  948. "N_assemble_les_3d: number of used cells %i\n", cell_type_count);
  949. if (cell_type_count == 0.0)
  950. G_fatal_error
  951. ("Not enough active cells [%i] to create the linear equation system. Check the cell status. Only active cells (value = 1) are used to create the equation system.",
  952. cell_type_count);
  953. /* allocate the memory for the linear equation system (les).
  954. * Only valid cells are used to create the les. */
  955. les = N_alloc_les_Ax_b(cell_type_count, les_type);
  956. index_ij = (int **)G_calloc(cell_type_count, sizeof(int *));
  957. for (i = 0; i < cell_type_count; i++)
  958. index_ij[i] = (int *)G_calloc(3, sizeof(int));
  959. count = 0;
  960. /*count the number of cells which should be used to create the linear equation system */
  961. /*save the k, i and j indices and create a ordered numbering */
  962. for (k = 0; k < geom->depths; k++) {
  963. for (j = 0; j < geom->rows; j++) {
  964. for (i = 0; i < geom->cols; i++) {
  965. if (cell_type == N_CELL_DIRICHLET) {
  966. if (N_CELL_INACTIVE <
  967. (int)N_get_array_3d_d_value(status, i, j, k) &&
  968. (int)N_get_array_3d_d_value(status, i, j,
  969. k) < N_MAX_CELL_STATE) {
  970. N_put_array_3d_d_value(cell_count, i, j, k, count);
  971. index_ij[count][0] = i;
  972. index_ij[count][1] = j;
  973. index_ij[count][2] = k;
  974. count++;
  975. G_debug(5,
  976. "N_assemble_les_3d: non-inactive cells count %i at pos x[%i] y[%i] z[%i]\n",
  977. count, i, j, k);
  978. }
  979. }
  980. else if (N_CELL_ACTIVE ==
  981. (int)N_get_array_3d_d_value(status, i, j, k)) {
  982. N_put_array_3d_d_value(cell_count, i, j, k, count);
  983. index_ij[count][0] = i;
  984. index_ij[count][1] = j;
  985. index_ij[count][2] = k;
  986. count++;
  987. G_debug(5,
  988. "N_assemble_les_3d: active cells count %i at pos x[%i] y[%i] z[%i]\n",
  989. count, i, j, k);
  990. }
  991. }
  992. }
  993. }
  994. G_debug(2, "N_assemble_les_3d: starting the parallel assemble loop");
  995. #pragma omp parallel for private(i, j, k, pos, count) schedule(static)
  996. for (count = 0; count < cell_type_count; count++) {
  997. i = index_ij[count][0];
  998. j = index_ij[count][1];
  999. k = index_ij[count][2];
  1000. /*create the entries for the */
  1001. N_data_star *items = call->callback(data, geom, i, j, k);
  1002. G_math_spvector *spvect = NULL;
  1003. /*allocate a sprase vector */
  1004. if (les_type == N_SPARSE_LES)
  1005. spvect = G_math_alloc_spvector(items->count);
  1006. /* initial conditions */
  1007. les->x[count] = N_get_array_3d_d_value(start_val, i, j, k);
  1008. /* the entry in the vector b */
  1009. les->b[count] = items->V;
  1010. /* pos describes the position in the sparse vector.
  1011. * the first entry is always the diagonal entry of the matrix*/
  1012. pos = 0;
  1013. if (les_type == N_SPARSE_LES) {
  1014. spvect->index[pos] = count;
  1015. spvect->values[pos] = items->C;
  1016. }
  1017. else {
  1018. les->A[count][count] = items->C;
  1019. }
  1020. /* western neighbour, entry is col - 1 */
  1021. if (i > 0) {
  1022. pos =
  1023. make_les_entry_3d(i, j, k, -1, 0, 0, count, pos, les, spvect,
  1024. cell_count, status, start_val, items->W,
  1025. cell_type);
  1026. }
  1027. /* eastern neighbour, entry col + 1 */
  1028. if (i < geom->cols - 1) {
  1029. pos = make_les_entry_3d(i, j, k, 1, 0, 0, count, pos, les, spvect,
  1030. cell_count, status, start_val, items->E,
  1031. cell_type);
  1032. }
  1033. /* northern neighbour, entry row -1 */
  1034. if (j > 0) {
  1035. pos =
  1036. make_les_entry_3d(i, j, k, 0, -1, 0, count, pos, les, spvect,
  1037. cell_count, status, start_val, items->N,
  1038. cell_type);
  1039. }
  1040. /* southern neighbour, entry row +1 */
  1041. if (j < geom->rows - 1) {
  1042. pos = make_les_entry_3d(i, j, k, 0, 1, 0, count, pos, les, spvect,
  1043. cell_count, status, start_val, items->S,
  1044. cell_type);
  1045. }
  1046. /*only for a 7 star entry needed */
  1047. if (items->type == N_7_POINT_STAR || items->type == N_27_POINT_STAR) {
  1048. /* the upper cell (top), entry depth + 1 */
  1049. if (k < geom->depths - 1) {
  1050. pos =
  1051. make_les_entry_3d(i, j, k, 0, 0, 1, count, pos, les,
  1052. spvect, cell_count, status, start_val,
  1053. items->T, cell_type);
  1054. }
  1055. /* the lower cell (bottom), entry depth - 1 */
  1056. if (k > 0) {
  1057. pos =
  1058. make_les_entry_3d(i, j, k, 0, 0, -1, count, pos, les,
  1059. spvect, cell_count, status, start_val,
  1060. items->B, cell_type);
  1061. }
  1062. }
  1063. /*How many entries in the les */
  1064. if (les->type == N_SPARSE_LES) {
  1065. spvect->cols = pos + 1;
  1066. G_math_add_spvector(les->Asp, spvect, count);
  1067. }
  1068. if (items)
  1069. G_free(items);
  1070. }
  1071. N_free_array_3d(cell_count);
  1072. for (i = 0; i < cell_type_count; i++)
  1073. G_free(index_ij[i]);
  1074. G_free(index_ij);
  1075. return les;
  1076. }
  1077. /*!
  1078. * \brief Integrate Dirichlet or Transmission boundary conditions into the les (3d)
  1079. *
  1080. * Dirichlet and Transmission boundary conditions will be integrated into
  1081. * the provided linear equation system. This is meaningfull if
  1082. * the les was created with #N_assemble_les_2d_dirichlet, because in
  1083. * this case Dirichlet boundary conditions are not automatically included.
  1084. *
  1085. * The provided les will be modified:
  1086. *
  1087. * Ax = b will be split into Ax_u + Ax_d = b
  1088. *
  1089. * x_u - the unknowns
  1090. * x_d - the Dirichlet cells
  1091. *
  1092. * Ax_u = b -Ax_d will be computed. Then the matrix A will be modified to
  1093. *
  1094. * | A_u 0 | x_u
  1095. * | 0 I | x_d
  1096. *
  1097. * \param les N_les* -- the linear equation system
  1098. * \param geom N_geom_data* -- geometrical data information
  1099. * \param status N_array_2d* -- the status array containing the cell types
  1100. * \param start_val N_array_2d* -- an array with start values
  1101. * \return int -- 1 = success, 0 = failure
  1102. * */
  1103. int N_les_integrate_dirichlet_3d(N_les * les, N_geom_data * geom,
  1104. N_array_3d * status, N_array_3d * start_val)
  1105. {
  1106. int rows, cols, depths;
  1107. int count = 0;
  1108. int i, j, x, y, z, stat;
  1109. double *dvect1;
  1110. double *dvect2;
  1111. G_debug(2,
  1112. "N_les_integrate_dirichlet_3d: integrating the dirichlet boundary condition");
  1113. rows = geom->rows;
  1114. cols = geom->cols;
  1115. depths = geom->depths;
  1116. /*we nned to additional vectors */
  1117. dvect1 = (double *)G_calloc(les->cols, sizeof(double));
  1118. dvect2 = (double *)G_calloc(les->cols, sizeof(double));
  1119. /*fill the first one with the x vector data of Dirichlet cells */
  1120. count = 0;
  1121. for (z = 0; z < depths; z++) {
  1122. for (y = 0; y < rows; y++) {
  1123. for (x = 0; x < cols; x++) {
  1124. stat = (int)N_get_array_3d_d_value(status, x, y, z);
  1125. if (stat > N_CELL_ACTIVE && stat < N_MAX_CELL_STATE) {
  1126. dvect1[count] =
  1127. N_get_array_3d_d_value(start_val, x, y, z);
  1128. count++;
  1129. }
  1130. else if (stat == N_CELL_ACTIVE) {
  1131. dvect1[count] = 0.0;
  1132. count++;
  1133. }
  1134. }
  1135. }
  1136. }
  1137. #pragma omp parallel default(shared)
  1138. {
  1139. /*perform the matrix vector product and */
  1140. if (les->type == N_SPARSE_LES)
  1141. G_math_Ax_sparse(les->Asp, dvect1, dvect2, les->rows);
  1142. else
  1143. G_math_d_Ax(les->A, dvect1, dvect2, les->rows, les->cols);
  1144. #pragma omp for schedule (static) private(i)
  1145. for (i = 0; i < les->cols; i++)
  1146. les->b[i] = les->b[i] - dvect2[i];
  1147. }
  1148. /*now set the Dirichlet cell rows and cols to zero and the
  1149. * diagonal entry to 1*/
  1150. count = 0;
  1151. for (z = 0; z < depths; z++) {
  1152. for (y = 0; y < rows; y++) {
  1153. for (x = 0; x < cols; x++) {
  1154. stat = (int)N_get_array_3d_d_value(status, x, y, z);
  1155. if (stat > N_CELL_ACTIVE && stat < N_MAX_CELL_STATE) {
  1156. if (les->type == N_SPARSE_LES) {
  1157. /*set the rows to zero */
  1158. for (i = 0; i < les->Asp[count]->cols; i++)
  1159. les->Asp[count]->values[i] = 0.0;
  1160. /*set the cols to zero */
  1161. for (i = 0; i < les->rows; i++) {
  1162. for (j = 0; j < les->Asp[i]->cols; j++) {
  1163. if (les->Asp[i]->index[j] == count)
  1164. les->Asp[i]->values[j] = 0.0;
  1165. }
  1166. }
  1167. /*entry on the diagonal */
  1168. les->Asp[count]->values[0] = 1.0;
  1169. }
  1170. else {
  1171. /*set the rows to zero */
  1172. for (i = 0; i < les->cols; i++)
  1173. les->A[count][i] = 0.0;
  1174. /*set the cols to zero */
  1175. for (i = 0; i < les->rows; i++)
  1176. les->A[i][count] = 0.0;
  1177. /*entry on the diagonal */
  1178. les->A[count][count] = 1.0;
  1179. }
  1180. }
  1181. count++;
  1182. }
  1183. }
  1184. }
  1185. return 0;
  1186. }
  1187. /* **************************************************************** */
  1188. /* **** make an entry in the les (3d) ***************************** */
  1189. /* **************************************************************** */
  1190. int make_les_entry_3d(int i, int j, int k, int offset_i, int offset_j,
  1191. int offset_k, int count, int pos, N_les * les,
  1192. G_math_spvector * spvect, N_array_3d * cell_count,
  1193. N_array_3d * status, N_array_3d * start_val,
  1194. double entry, int cell_type)
  1195. {
  1196. int K;
  1197. int di = offset_i;
  1198. int dj = offset_j;
  1199. int dk = offset_k;
  1200. K = (int)N_get_array_3d_d_value(cell_count, i + di, j + dj, k + dk) -
  1201. (int)N_get_array_3d_d_value(cell_count, i, j, k);
  1202. if (cell_type == N_CELL_ACTIVE) {
  1203. if ((int)N_get_array_3d_d_value(status, i + di, j + dj, k + dk) >
  1204. N_CELL_ACTIVE &&
  1205. (int)N_get_array_3d_d_value(status, i + di, j + dj,
  1206. k + dk) < N_MAX_CELL_STATE)
  1207. les->b[count] -=
  1208. N_get_array_3d_d_value(start_val, i + di, j + dj,
  1209. k + dk) * entry;
  1210. else if ((int)N_get_array_3d_d_value(status, i + di, j + dj, k + dk)
  1211. == N_CELL_ACTIVE) {
  1212. if ((count + K) >= 0 && (count + K) < les->cols) {
  1213. G_debug(5,
  1214. " make_les_entry_3d: (N_CELL_ACTIVE) create matrix entry at row[%i] col[%i] value %g\n",
  1215. count, count + K, entry);
  1216. pos++;
  1217. if (les->type == N_SPARSE_LES) {
  1218. spvect->index[pos] = count + K;
  1219. spvect->values[pos] = entry;
  1220. }
  1221. else {
  1222. les->A[count][count + K] = entry;
  1223. }
  1224. }
  1225. }
  1226. }
  1227. else if (cell_type == N_CELL_DIRICHLET) {
  1228. if ((int)N_get_array_3d_d_value(status, i + di, j + dj, k + dk)
  1229. != N_CELL_INACTIVE) {
  1230. if ((count + K) >= 0 && (count + K) < les->cols) {
  1231. G_debug(5,
  1232. " make_les_entry_3d: (N_CELL_DIRICHLET) create matrix entry at row[%i] col[%i] value %g\n",
  1233. count, count + K, entry);
  1234. pos++;
  1235. if (les->type == N_SPARSE_LES) {
  1236. spvect->index[pos] = count + K;
  1237. spvect->values[pos] = entry;
  1238. }
  1239. else {
  1240. les->A[count][count + K] = entry;
  1241. }
  1242. }
  1243. }
  1244. }
  1245. return pos;
  1246. }