1
0

diffusion_w_gtk_ctrl.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467
  1. // 包括库 --- Include libraries
  2. #include <stdio.h>
  3. #include <math.h>
  4. #include <gtk/gtk.h> // GUI, Gtk Lib
  5. // 定义 --- Definitions
  6. //
  7. // 绘制时空浓度输出的像素贴图尺寸 --- Pixmap dimensions to paint the space-time-concentration output
  8. #define X_SIZE 256
  9. #define Y_SIZE 512
  10. // 状态变量的范围 --- Range of the state variable
  11. // 浓度最大值 --- Max value of concentratiom
  12. #define MAX_CONCENTRATION 100
  13. // 浓度最小值 --- Min value of concentration
  14. #define MIN_CONTENTRATION 0
  15. // 彩色贴图渐变点数 --- Color map gradient number of points
  16. #define N_GRADIENT_POINTS 128 //
  17. #define N X_SIZE // 空间网格数 --- Number of spatial grid points
  18. #define T Y_SIZE // 时间步数 --- Time steps to be simulated (integrated)
  19. #define dt 1 // 时间步长 --- Temporal length scale (dt)
  20. #define dx 1 // 空间步长 --- Spatial length scale (dx)
  21. #define diffusion_rate 0.45 // 扩散系数 --- Diffusion coefficient
  22. // 全球结构 --- Global structures
  23. // 颜色贴图渐变 --- color-map gradient
  24. struct colorGradient{
  25. int red[(int) N_GRADIENT_POINTS], green[(int) N_GRADIENT_POINTS], blue[(int) N_GRADIENT_POINTS];
  26. } color;
  27. // 状态梯度映射 --- state-gradient mapping
  28. struct stateGradientMap {
  29. float Delta, delta;
  30. } gradientMapping;
  31. // 模拟数据 --- simulation data
  32. struct simulationData{
  33. gint run_id; // time handler tag for a simulation run
  34. gboolean running;
  35. gboolean initialized;
  36. double u[N]; // u: 为当前时刻的浓度分
  37. // --- To store the concentration distribution at the current moment
  38. int generation_time; // generation: 模拟迭代 --- simulation iteration
  39. double time_buffer[N][T]; // store T denerations (dt) to display as a pixmap
  40. } state;
  41. // 函数声明 --- Function declarations
  42. // Declare PUT PIXEL function to access individual pixel data on a Pixel Buffer.
  43. //Implemented at the end of documment under main block
  44. void put_pixel(GdkPixbuf *pixbuf, int x, int y, guchar red, guchar green, guchar blue, guchar alpha);
  45. // Function to actually paint the temporal Buffer to a pixmap
  46. static void paint_time_buffer (gpointer data);
  47. struct stateGradientMap make_state_gradient_map(){
  48. struct stateGradientMap gradient_mapping;
  49. gradient_mapping.Delta = (float) (MAX_CONCENTRATION - MIN_CONTENTRATION);
  50. gradient_mapping.delta = gradient_mapping.Delta / (float)N_GRADIENT_POINTS;
  51. return gradient_mapping;
  52. }
  53. // Constructure-like function to make/create/construct a color structure
  54. // n_points can be at MAX the same as N_GRADIENT_POINTS
  55. struct colorGradient make_color_gradient(int n_points){
  56. struct colorGradient color;
  57. for(int value = 1; value <= n_points;value ++)
  58. {
  59. float ratio;
  60. float min = (float) 1;
  61. float max = (float) n_points;
  62. ratio = 2 * (value-min) / (max - min);
  63. if (ratio < 1 ){color.blue[value] = (int)(255*(1 - ratio));}else{color.blue[value]=0;};
  64. if (ratio > 1 ){color.red[value] = (int)(255*(ratio - 1));}else{color.red[value]=0;};
  65. color.green[value] = 255 - color.blue[value] - color.red[value];
  66. printf("making a gradient with %d points\n", n_points);
  67. printf("%d ---> [ %d %d %d ] ratio = %f\n", value,color.red[value],color.green[value],color.blue[value], ratio);
  68. }
  69. return color;
  70. }
  71. // 获取梯度函数 --- get gradient fdrom state functions
  72. // from a single site
  73. float get_gradient_at_location(int site){
  74. float value;
  75. if (state.u[site] != MIN_CONTENTRATION)
  76. {value = ceil((state.u[site]-((float)MIN_CONTENTRATION))/gradientMapping.delta);}
  77. else{value = 1;}
  78. return value;
  79. }
  80. // from a time buffuer point
  81. float get_gradient_in_time_buffer(int site, int time){
  82. float value;
  83. if (state.time_buffer[site][time] != MIN_CONTENTRATION)
  84. {value = ceil((state.time_buffer[site][time]-((float)MIN_CONTENTRATION))/gradientMapping.delta);}
  85. else{value = 1;}
  86. return value;
  87. }
  88. // 打印颜色渐变状态 --- Print color-gradient function
  89. void print_gradient(void){
  90. // 根据状态变量计算梯度值 --- Calculate gradient value from state variable
  91. float value;
  92. // 代 --- generations
  93. printf("[color value:\t");
  94. // 最左边3个格点的状态 --- state of the 3 left-most lattice sites
  95. for (int i = 0; i < 3;i++){
  96. printf("%d ", (int) get_gradient_at_location(i));
  97. printf("\t");
  98. }
  99. printf("...\t");
  100. // 三个中心格点的状态 --- state of the 3 center lattice sites
  101. for (int i = floor(N/2)-1 ; i < floor(N/2)+2;i++){
  102. printf("%d ", (int) get_gradient_at_location(i));
  103. printf("\t");
  104. }
  105. printf("...\t");
  106. // 3个最右边格点的状态 --- state of the 3 right-most lattice sites
  107. for (int i = N-3; i < N;i++){
  108. printf("%d ", (int) get_gradient_at_location(i));
  109. printf("\t");
  110. }
  111. printf("\n");
  112. }
  113. // 打印功能 --- Print function (truncated)
  114. void print_grid(void){
  115. // 代 --- generations
  116. printf("[dt x %d]\t", state.generation_time);
  117. // 最左边3个格点的状态 --- state of the 3 left-most lattice sites
  118. for (int i = 0; i < 3;i++){
  119. printf("%.2f ", state.u[i]);
  120. printf("\t");
  121. }
  122. printf("...\t");
  123. // 三个中心格点的状态 --- state of the 3 center lattice sites
  124. for (int i = floor(N/2)-1 ; i < floor(N/2)+2;i++){
  125. printf("%.2f ", state.u[i]);
  126. printf("\t");
  127. }
  128. printf("...\t");
  129. // 3个最右边格点的状态 --- state of the 3 right-most lattice sites
  130. for (int i = N-3; i < N;i++){
  131. printf("%.2f ", state.u[i]);
  132. printf("\t");
  133. }
  134. printf("\n");
  135. }
  136. // 推送时间缓冲 --- Push time buffer
  137. void push_time_buffer(void){
  138. if (state.generation_time < (int)Y_SIZE)
  139. {
  140. for (int i=0; i < (int)X_SIZE; i++) state.time_buffer[i][state.generation_time]=state.u[i];
  141. }else{
  142. // for (int i=0; i < (int)X_SIZE; i++) state.time_buffer[i][state.generation_time%(int)Y_SIZE]=state.u[i];
  143. for (int t = 0; t < ((int)Y_SIZE-1); t++)
  144. for (int i = 0; i <(int)X_SIZE; i++)
  145. state.time_buffer[i][t]=state.time_buffer[i][t+1] ;
  146. for (int i = 0; i <(int)X_SIZE; i++)
  147. state.time_buffer[i][(int)Y_SIZE-1]= state.u[i];
  148. }
  149. }
  150. // 初始化功能 --- Initialization function
  151. static void on_button_init_lattice(GtkWidget *widget, gpointer data){
  152. // 初始化浓度分布 --- Initialize concentration distribution
  153. for (int i = 0; i < N; i++) {
  154. if (i >= 45*N/100 && i <= 55*N/100) {
  155. state.u[i] = (float) MAX_CONCENTRATION;
  156. } else {
  157. state.u[i] = 0.0;
  158. }
  159. }
  160. //for (int i = 0; i < N; i++) state.time_buffer[i][0]= state.u[i];
  161. state.initialized = TRUE;
  162. // 初始化时间 --- Initialize time
  163. state.generation_time = 0;
  164. push_time_buffer();
  165. paint_time_buffer (data);
  166. state.initialized = TRUE;
  167. g_print ("Lattice initialized\n");
  168. }
  169. void init_simulation_App(void){
  170. state.running = FALSE;
  171. state.initialized = FALSE;
  172. // prepare color gradient and its mapping to state variiable
  173. // 制作颜色渐变 --- Make a color gradient
  174. color = make_color_gradient((int) N_GRADIENT_POINTS);
  175. // 根据状态变量计算梯度值 --- Calculate gradient value from state variable
  176. gradientMapping = make_state_gradient_map();
  177. // Initialize time buffer
  178. for (int t = 0; t < T; t++)
  179. for (int i = 0; i < N; i++) state.time_buffer[i][t]=0.0;
  180. }
  181. // 更新功能 --- Update function (to increment one iteration/generation)
  182. void update_lattice(gpointer data){
  183. // u_new: 为下一个时刻的浓度分布
  184. double u_new[N];// --- To store the concentration distribution at the next moment
  185. // 强制边界条件 --- Enforce boundary condition
  186. u_new[0] = state.u[0];
  187. u_new[N] = state.u[N];
  188. // 内部节点计算 --- Internal node calculation (FTCS)
  189. for (int i = 1; i < N; i++) {
  190. u_new[i] = state.u[i] + (double)diffusion_rate * dt / (dx*dx) * (state.u[i+1] - 2*state.u[i] + state.u[i-1]);
  191. }
  192. // 更新浓度分布 --- Update concentration distribution
  193. for (int i = 0; i < N; i++) {
  194. state.u[i] = u_new[i];
  195. }
  196. state.generation_time ++;
  197. print_grid();
  198. print_gradient();
  199. push_time_buffer();
  200. paint_time_buffer (data);
  201. }
  202. /* Time handler to connect update function to the gtk loop */
  203. gboolean time_handler (gpointer data)
  204. {
  205. update_lattice (data);
  206. return TRUE;
  207. }
  208. // 应用程序数据初始化应用程序数据初始化 --- application data initialization
  209. void set_up_simulation_environment(void){
  210. // 初始化模拟 --- Initialize simulation
  211. init_simulation_App();
  212. print_grid();
  213. print_gradient();
  214. g_print ("Application data initialized\n");
  215. }
  216. // Control call_back functions
  217. /* Callback to start simulation */
  218. static void on_button_start_simulation (GtkWidget *button, gpointer data)
  219. {
  220. if(!state.running && state.initialized)
  221. {
  222. state.run_id = g_idle_add ((GSourceFunc) time_handler, GTK_IMAGE (data));
  223. state.running = TRUE;
  224. g_print ("Simulation started\n");
  225. }
  226. }
  227. static void on_button_stop_simulation (GtkWidget *button, gpointer data)
  228. {
  229. if (state.running)
  230. {
  231. g_source_remove (state.run_id);
  232. state.running = FALSE;
  233. g_print ("Simulation stopped\n");
  234. }
  235. }
  236. static void on_button_show_about(GtkWidget *widget, gpointer data)
  237. {
  238. GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file("X-Institute_logo_small.tif", NULL);
  239. GtkWidget *dialog = gtk_about_dialog_new();
  240. gtk_about_dialog_set_program_name (GTK_ABOUT_DIALOG(dialog),
  241. "Diffusion PDE, a Gtk simulation");
  242. gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(dialog), "version 0.0, 2024");
  243. gtk_about_dialog_set_copyright(GTK_ABOUT_DIALOG(dialog),"Open Source Code");
  244. gtk_about_dialog_set_comments(GTK_ABOUT_DIALOG(dialog),
  245. "Integrating the Diffusion PDE (FTCS)\n\nby: 许跃川 & 纪胡安");
  246. gtk_about_dialog_set_website(GTK_ABOUT_DIALOG(dialog),
  247. "https://git.xinstitute.org.cn/keymer/Diffusion");
  248. gtk_about_dialog_set_logo(GTK_ABOUT_DIALOG(dialog), pixbuf);
  249. g_object_unref(pixbuf), pixbuf = NULL;
  250. gtk_dialog_run(GTK_DIALOG (dialog));
  251. gtk_widget_destroy(dialog);
  252. }
  253. // 激活Gtk功能 --- Activate Gtk function
  254. static void activate (GtkApplication *app, gpointer user_data){
  255. // note this function is meant to only contain Gtk stuff
  256. set_up_simulation_environment(); // a bit of cheating
  257. // 声明小工具 --- declare Widgets
  258. GtkWidget *window, *grid, *image_space_time_concentration;
  259. // Gdk Pixel bufer to create an image
  260. GdkPixbuf *pixbuf;
  261. // 创建Gtk网格 --- Create a Gtk grid
  262. grid = gtk_grid_new ();
  263. // 创建新窗口 --- Create a new WINDOW
  264. window = gtk_application_window_new (app);
  265. // 设置窗口标题 --- Set window title
  266. gtk_window_set_title (GTK_WINDOW (window), "Diffusion (FTCS)");
  267. // 使窗口不可调整大小 --- Make window not resizable
  268. gtk_window_set_resizable (GTK_WINDOW(window), FALSE);
  269. // 创建像素缓冲区 --- Create Pixel buffer
  270. pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, 0, 8, X_SIZE, Y_SIZE);
  271. // 从像素缓冲区创建图像 --- Create Image from empty Pixel buffer
  272. image_space_time_concentration = gtk_image_new_from_pixbuf(pixbuf);
  273. // 绘制图像 --- Paint Image (use time-buffer data)
  274. paint_time_buffer(image_space_time_concentration);
  275. //将图像添加到网格 --- Add Image to grid container
  276. gtk_grid_attach (GTK_GRID (grid), image_space_time_concentration, 0, 7, 5, 1);
  277. // 模拟控制 --- Simulation Control
  278. GtkWidget *button, *ctrl_frame, *button_box;
  279. button_box = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL);
  280. ctrl_frame = gtk_frame_new ("Simulation Control");
  281. // Initialize
  282. button = gtk_button_new_with_label ("Init");
  283. g_signal_connect (button, "clicked", G_CALLBACK (on_button_init_lattice), GTK_IMAGE (image_space_time_concentration));
  284. gtk_container_add (GTK_CONTAINER (button_box), button);
  285. // Start
  286. button = gtk_button_new_with_label ("Start");
  287. g_signal_connect (button, "clicked", G_CALLBACK (on_button_start_simulation), GTK_IMAGE (image_space_time_concentration));
  288. gtk_container_add (GTK_CONTAINER (button_box), button);
  289. // Stop
  290. button = gtk_button_new_with_label ("Stop");
  291. g_signal_connect (button, "clicked", G_CALLBACK (on_button_stop_simulation), NULL);
  292. gtk_container_add (GTK_CONTAINER (button_box), button);
  293. // About
  294. button = gtk_button_new_with_label ("About");
  295. g_signal_connect (button, "clicked", G_CALLBACK (on_button_show_about), NULL);
  296. gtk_container_add (GTK_CONTAINER (button_box), button);
  297. // Quit
  298. button = gtk_button_new_with_label ("Quit");
  299. g_signal_connect (button, "clicked", G_CALLBACK (on_button_stop_simulation), NULL);
  300. g_signal_connect_swapped (button, "clicked", G_CALLBACK (gtk_widget_destroy), window);
  301. gtk_container_add (GTK_CONTAINER (button_box), button);
  302. gtk_container_add (GTK_CONTAINER (ctrl_frame), button_box);
  303. gtk_grid_attach (GTK_GRID (grid), ctrl_frame, 0, 8, 5, 1);
  304. // 将网格添加到窗口 --- Add grid to the window
  305. gtk_container_add (GTK_CONTAINER (window), grid);
  306. // 显示窗口及其小工具 --- Show the window and its Widgets
  307. gtk_widget_show_all (window);
  308. }
  309. // 主要功能 --- Main function
  310. int main(int argc, char **argv){
  311. GtkApplication *app;
  312. int status;
  313. app = gtk_application_new ("keymer.lab.yuechuan.diffusion.FTCS", G_APPLICATION_FLAGS_NONE);
  314. g_signal_connect (app, "activate", G_CALLBACK (activate), NULL);
  315. status = g_application_run (G_APPLICATION (app), argc, argv);
  316. g_object_unref (app);
  317. return status;
  318. }
  319. static void paint_time_buffer (gpointer data){
  320. // 创建像素缓冲区 --- Create Pixel buffer
  321. GdkPixbuf *p;
  322. float value;
  323. p = gdk_pixbuf_new (GDK_COLORSPACE_RGB, 0, 8, X_SIZE, Y_SIZE);
  324. // 绘制(使用put_pixel) --- Paint (using put_pixel)
  325. int x,y, site, time;
  326. for (site = 0; site < X_SIZE; site++) // 空间 --- Space
  327. {
  328. for (time = 0; time < Y_SIZE; time++) // 时间 --- Time
  329. {
  330. // 从状态获取梯度值 --- get gradient value from state
  331. value = get_gradient_in_time_buffer(site,time);
  332. // 油漆 --- paint
  333. x = site;
  334. y = time;
  335. put_pixel (p, (int) x, (int) y,
  336. (guchar) color.red[(int)value],
  337. (guchar) color.green[(int)value],
  338. (guchar) color.blue[(int)value],
  339. 255);
  340. }
  341. }
  342. // 从缓冲区创建图像 --- Create image (data) from buffer
  343. gtk_image_set_from_pixbuf (GTK_IMAGE (data), GDK_PIXBUF (p));
  344. // 释放缓冲存储器 --- Release buffer memory
  345. g_object_unref (p);
  346. };
  347. // put_pixel的实现 --- Implementation of put_pixel.
  348. // Thanks to code from:
  349. // https://developer.gnome.org/gdk-pixbuf/stable/gdk-pixbuf-The-GdkPixbuf-Structure.html
  350. void put_pixel(GdkPixbuf *pixbuf, int x, int y, guchar red, guchar green, guchar blue, guchar alpha){
  351. guchar *pixels, *p;
  352. int rowstride, numchannels;
  353. numchannels = gdk_pixbuf_get_n_channels(pixbuf);
  354. rowstride = gdk_pixbuf_get_rowstride(pixbuf);
  355. pixels = gdk_pixbuf_get_pixels(pixbuf);
  356. p = pixels + y * rowstride + x * numchannels;
  357. p[0] = red; p[1] = green; p[2] = blue; p[3] = alpha;
  358. }