diffusion_w_gtk.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  1. // 包括库 --- Include libraries
  2. #include <stdio.h>
  3. #include <math.h>
  4. #include <gtk/gtk.h> // GUI, Gtk Lib
  5. // 绘制时空浓度输出的像素贴图尺寸 --- Pixmap dimensions to paint the space-time-concentration output
  6. #define X_SIZE 256
  7. #define Y_SIZE 512
  8. // 状态变量的范围 --- Range of the state variable
  9. // 浓度最大值 --- Max value of concentratiom
  10. #define MAX_CONCENTRATION 100
  11. // 浓度最小值 --- Min value of concentration
  12. #define MIN_CONTENTRATION 0
  13. // 彩色贴图渐变点数 --- Color map gradient number of points
  14. #define N_GRADIENT_POINTS 1000 //
  15. // 定义 --- Definitions
  16. #define N X_SIZE // 空间网格数 --- Number of spatial grid points
  17. #define T Y_SIZE // 时间步数 --- Time steps to be simulated (integrated)
  18. #define dt 1 // 时间步长 --- Temporal length scale (dt)
  19. #define dx 1 // 空间步长 --- Spatial length scale (dx)
  20. #define diffusion_rate 0.45 // 扩散系数 --- Diffusion coefficient
  21. // 全球结构 --- Global structures
  22. // 颜色贴图渐变 --- color-map gradient
  23. struct color_gradient{
  24. int red[(int) N_GRADIENT_POINTS], green[(int) N_GRADIENT_POINTS], blue[(int) N_GRADIENT_POINTS];
  25. } color;
  26. // 模拟数据 --- simulation data
  27. struct simulation_data{
  28. double u[N]; // u: 为当前时刻的浓度分
  29. // --- To store the concentration distribution at the current moment
  30. int generation; // generation: 模拟迭代 --- simulation iteration
  31. double time_buffer[N][T]; // store T denerations (dt) to display as a pixmap
  32. } state;
  33. // 函数声明 --- Function declarations
  34. // Declare PUT PIXEL function to access individual pixel data on a Pixel Buffer.
  35. //Implemented at the end of documment under main block
  36. void put_pixel(GdkPixbuf *pixbuf, int x, int y, guchar red, guchar green, guchar blue, guchar alpha);
  37. // Function to actually paint the temporal Buffer to a pixmap
  38. static void paint_time_buffer (gpointer data);
  39. // Constructure-like function to make/create/construct a color structure
  40. // n_points can be at MAX the same as N_GRADIENT_POINTS
  41. struct color_gradient makeColorGradient(int n_points){
  42. struct color_gradient color;
  43. for(int value = 1; value <= n_points;value ++)
  44. {
  45. float ratio;
  46. float min = (float) 1;
  47. float max = (float) n_points;
  48. ratio = 2 * (value-min) / (max - min);
  49. if (ratio < 1 ){color.blue[value] = (int)(255*(1 - ratio));}else{color.blue[value]=0;};
  50. if (ratio > 1 ){color.red[value] = (int)(255*(ratio - 1));}else{color.red[value]=0;};
  51. color.green[value] = 255 - color.blue[value] - color.red[value];
  52. printf("making a gradient with %d points\n", n_points);
  53. printf("%d ---> [ %d %d %d ] ratio = %f\n", value,color.red[value],color.green[value],color.blue[value], ratio);
  54. }
  55. return color;
  56. }
  57. // 打印颜色渐变状态 --- Print color-gradient function
  58. void printGradient(void){
  59. // 根据状态变量计算梯度值 --- Calculate gradient value from state variable
  60. float Delta, delta, value;
  61. Delta = (float) (MAX_CONCENTRATION - MIN_CONTENTRATION);
  62. delta = Delta / (float)N_GRADIENT_POINTS;
  63. // 代 --- generations
  64. printf("[color value:\t");
  65. // 最左边3个格点的状态 --- state of the 3 left-most lattice sites
  66. for (int i = 0; i < 3;i++){
  67. if (state.u[i] != MIN_CONTENTRATION)
  68. {value = ceil((state.u[i]-((float)MIN_CONTENTRATION))/delta);}
  69. else{value = 1;}
  70. printf("%d ", (int) value);
  71. printf("\t");
  72. }
  73. printf("...\t");
  74. // 三个中心格点的状态 --- state of the 3 center lattice sites
  75. for (int i = floor(N/2)-1 ; i < floor(N/2)+2;i++){
  76. if (state.u[i] != MIN_CONTENTRATION)
  77. {value = ceil((state.u[i]-((float)MIN_CONTENTRATION))/delta);}
  78. else{value = 1;}
  79. printf("%d ", (int) value);
  80. printf("\t");
  81. }
  82. printf("...\t");
  83. // 3个最右边格点的状态 --- state of the 3 right-most lattice sites
  84. for (int i = N-3; i < N;i++){
  85. if (state.u[i] != MIN_CONTENTRATION)
  86. {value = ceil((state.u[i]-((float)MIN_CONTENTRATION))/delta);}
  87. else{value = 1;}
  88. printf("%d ", (int) value);
  89. printf("\t");
  90. }
  91. printf("\n");
  92. }
  93. // 打印功能 --- Print function (truncated)
  94. void printGrid(void){
  95. // 代 --- generations
  96. printf("[dt x %d]\t", state.generation);
  97. // 最左边3个格点的状态 --- state of the 3 left-most lattice sites
  98. for (int i = 0; i < 3;i++){
  99. printf("%.2f ", state.u[i]);
  100. printf("\t");
  101. }
  102. printf("...\t");
  103. // 三个中心格点的状态 --- state of the 3 center lattice sites
  104. for (int i = floor(N/2)-1 ; i < floor(N/2)+2;i++){
  105. printf("%.2f ", state.u[i]);
  106. printf("\t");
  107. }
  108. printf("...\t");
  109. // 3个最右边格点的状态 --- state of the 3 right-most lattice sites
  110. for (int i = N-3; i < N;i++){
  111. printf("%.2f ", state.u[i]);
  112. printf("\t");
  113. }
  114. printf("\n");
  115. }
  116. // 初始化功能 --- Initialization function
  117. void initLattice(void){
  118. for (int t = 0; t < T; t++) for (int i = 0; i < N; i++) state.time_buffer[i][t]=0.0;
  119. // 初始化浓度分布 --- Initialize concentration distribution
  120. for (int i = 0; i < N; i++) {
  121. if (i >= 45*N/100 && i <= 55*N/100) {
  122. state.u[i] = (float) MAX_CONCENTRATION;
  123. } else {
  124. state.u[i] = 0.0;
  125. }
  126. }
  127. for (int i = 0; i < N; i++) state.time_buffer[i][0]= state.u[i];
  128. // 初始化时间 --- Initialize time
  129. state.generation = 0;
  130. }
  131. // 更新功能 --- Update function (to increment one iteration/generation)
  132. void updateLattice(void){
  133. // u_new: 为下一个时刻的浓度分布
  134. double u_new[N];// --- To store the concentration distribution at the next moment
  135. // 强制边界条件 --- Enforce boundary condition
  136. u_new[0] = state.u[0];
  137. u_new[N] = state.u[N];
  138. // 内部节点计算 --- Internal node calculation
  139. for (int i = 1; i < N; i++) {
  140. u_new[i] = state.u[i] + (double)diffusion_rate * dt / (dx*dx) * (state.u[i+1] - 2*state.u[i] + state.u[i-1]);
  141. }
  142. // 更新浓度分布 --- Update concentration distribution
  143. for (int i = 0; i < N; i++) {
  144. state.u[i] = u_new[i];
  145. }
  146. state.generation ++;
  147. }
  148. // 推送时间缓冲 --- Push time buffer
  149. void pushTimeBuffer(int time){
  150. for (int i=0; i < N; i++) state.time_buffer[i][time]=state.u[i];
  151. }
  152. // 模拟 --- simulation
  153. void integrateSimulation(void){
  154. // 初始化模拟 --- Initialize simulation
  155. initLattice();
  156. printGrid();
  157. printGradient();
  158. // 迭代计算 --- Iterative calculation
  159. for (int t = 1; t < T; t++) {
  160. updateLattice();
  161. pushTimeBuffer(t);
  162. printGrid();
  163. printGradient();
  164. }
  165. }
  166. // Activate Gtk function
  167. static void activate (GtkApplication *app, gpointer user_data){
  168. integrateSimulation();
  169. // 声明小工具 --- declare Widgets
  170. GtkWidget *window, *image_space_time_concentration;
  171. // Gdk Pixel bufer to create an image
  172. GdkPixbuf *pixbuf;
  173. // 创建小部件:一个新的窗口 --- Create widgets: a new WINDOW
  174. window = gtk_application_window_new (app);
  175. // 设置窗口标题 --- Set window title
  176. gtk_window_set_title (GTK_WINDOW (window), "Diffusion (FTCS)");
  177. // 使窗口不可调整大小 --- Make window not resizable
  178. gtk_window_set_resizable (GTK_WINDOW(window), FALSE);
  179. // 创建像素缓冲区 --- Create Pixel buffer
  180. pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, 0, 8, X_SIZE, Y_SIZE);
  181. // 从像素缓冲区创建图像 --- Create Image from empty Pixel buffer
  182. image_space_time_concentration = gtk_image_new_from_pixbuf(pixbuf);
  183. // 绘制图像 --- Paint Image (use time-buffer data)
  184. paint_time_buffer(image_space_time_concentration);
  185. // 将图像添加到窗口容器 --- Add Image to window container
  186. gtk_container_add (GTK_CONTAINER (window), image_space_time_concentration);
  187. // 显示窗口及其小工具 --- Show the window and its Widgets
  188. gtk_widget_show_all (window);
  189. }
  190. // 主要功能 --- Main function
  191. int main(int argc, char **argv){
  192. GtkApplication *app;
  193. int status;
  194. app = gtk_application_new ("keymer.lab.yuechuan.diffusion", G_APPLICATION_FLAGS_NONE);
  195. g_signal_connect (app, "activate", G_CALLBACK (activate), NULL);
  196. status = g_application_run (G_APPLICATION (app), argc, argv);
  197. g_object_unref (app);
  198. return status;
  199. }
  200. static void paint_time_buffer (gpointer data){
  201. // 创建像素缓冲区 --- Create Pixel buffer
  202. GdkPixbuf *p;
  203. p = gdk_pixbuf_new (GDK_COLORSPACE_RGB, 0, 8, X_SIZE, Y_SIZE);
  204. // 制作颜色渐变 --- Make a color gradient
  205. color = makeColorGradient((int) N_GRADIENT_POINTS);
  206. // 根据状态变量计算梯度值 --- Calculate gradient value from state variable
  207. float Delta, delta, value;
  208. Delta = (float) (MAX_CONCENTRATION - MIN_CONTENTRATION);
  209. delta = Delta / (float)N_GRADIENT_POINTS;
  210. // 绘制(使用put_pixel) --- Paint (using put_pixel)
  211. int x, y;
  212. for (x = 0; x < X_SIZE; x++) // 空间 --- Space
  213. {
  214. for (y = 0; y < Y_SIZE; y++) // 时间 --- Time
  215. {
  216. // 从状态获取梯度值 --- get gradient value from state
  217. if (state.time_buffer[x][y] != MIN_CONTENTRATION)
  218. {value = ceil((state.time_buffer[x][y]-((float)MIN_CONTENTRATION))/delta);}
  219. else{value = 1;}
  220. // 油漆 --- paint
  221. put_pixel (p, (int) x, (int) y,
  222. (guchar) color.red[(int)value],
  223. (guchar) color.green[(int)value],
  224. (guchar) color.blue[(int)value],
  225. 255);
  226. }
  227. }
  228. // 从缓冲区创建图像 --- Create image (data) from buffer
  229. gtk_image_set_from_pixbuf (GTK_IMAGE (data), GDK_PIXBUF (p));
  230. // 释放缓冲存储器 --- Release buffer memory
  231. g_object_unref (p);
  232. };
  233. // put_pixel的实现 --- Implementation of put_pixel.
  234. // Thanks to code from:
  235. // https://developer.gnome.org/gdk-pixbuf/stable/gdk-pixbuf-The-GdkPixbuf-Structure.html
  236. void put_pixel(GdkPixbuf *pixbuf, int x, int y, guchar red, guchar green, guchar blue, guchar alpha){
  237. guchar *pixels, *p;
  238. int rowstride, numchannels;
  239. numchannels = gdk_pixbuf_get_n_channels(pixbuf);
  240. rowstride = gdk_pixbuf_get_rowstride(pixbuf);
  241. pixels = gdk_pixbuf_get_pixels(pixbuf);
  242. p = pixels + y * rowstride + x * numchannels;
  243. p[0] = red; p[1] = green; p[2] = blue; p[3] = alpha;
  244. }