// 包括库 --- Include libraries #include #include #include // GUI, Gtk Lib // 定义 --- Definitions // // 绘制时空浓度输出的像素贴图尺寸 --- Pixmap dimensions to paint the space-time-concentration output #define X_SIZE 256 #define Y_SIZE 512 // 状态变量的范围 --- Range of the state variable // 浓度最大值 --- Max value of concentratiom #define MAX_CONCENTRATION 100 // 浓度最小值 --- Min value of concentration #define MIN_CONTENTRATION 0 // 彩色贴图渐变点数 --- Color map gradient number of points #define N_GRADIENT_POINTS 128 // #define N X_SIZE // 空间网格数 --- Number of spatial grid points #define T Y_SIZE // 时间步数 --- Time steps to be simulated (integrated) #define dt 1 // 时间步长 --- Temporal length scale (dt) #define dx 1 // 空间步长 --- Spatial length scale (dx) #define diffusion_rate 0.45 // 扩散系数 --- Diffusion coefficient // 全球结构 --- Global structures // 颜色贴图渐变 --- color-map gradient struct colorGradient{ int red[(int) N_GRADIENT_POINTS], green[(int) N_GRADIENT_POINTS], blue[(int) N_GRADIENT_POINTS]; } color; // 状态梯度映射 --- state-gradient mapping struct stateGradientMap { float Delta, delta; } gradientMapping; // 模拟数据 --- simulation data struct simulationData{ gint run_id; // time handler tag for a simulation run gboolean running; gboolean initialized; double u[N]; // u: 为当前时刻的浓度分 // --- To store the concentration distribution at the current moment int generation_time; // generation: 模拟迭代 --- simulation iteration double time_buffer[N][T]; // store T denerations (dt) to display as a pixmap } state; // 函数声明 --- Function declarations // Declare PUT PIXEL function to access individual pixel data on a Pixel Buffer. //Implemented at the end of documment under main block void put_pixel(GdkPixbuf *pixbuf, int x, int y, guchar red, guchar green, guchar blue, guchar alpha); // Function to actually paint the temporal Buffer to a pixmap static void paint_time_buffer (gpointer data); struct stateGradientMap make_state_gradient_map(){ struct stateGradientMap gradient_mapping; gradient_mapping.Delta = (float) (MAX_CONCENTRATION - MIN_CONTENTRATION); gradient_mapping.delta = gradient_mapping.Delta / (float)N_GRADIENT_POINTS; return gradient_mapping; } // Constructure-like function to make/create/construct a color structure // n_points can be at MAX the same as N_GRADIENT_POINTS struct colorGradient make_color_gradient(int n_points){ struct colorGradient color; for(int value = 1; value <= n_points;value ++) { float ratio; float min = (float) 1; float max = (float) n_points; ratio = 2 * (value-min) / (max - min); if (ratio < 1 ){color.blue[value] = (int)(255*(1 - ratio));}else{color.blue[value]=0;}; if (ratio > 1 ){color.red[value] = (int)(255*(ratio - 1));}else{color.red[value]=0;}; color.green[value] = 255 - color.blue[value] - color.red[value]; printf("making a gradient with %d points\n", n_points); printf("%d ---> [ %d %d %d ] ratio = %f\n", value,color.red[value],color.green[value],color.blue[value], ratio); } return color; } // 获取梯度函数 --- get gradient fdrom state functions // from a single site float get_gradient_at_location(int site){ float value; if (state.u[site] != MIN_CONTENTRATION) {value = ceil((state.u[site]-((float)MIN_CONTENTRATION))/gradientMapping.delta);} else{value = 1;} return value; } // from a time buffuer point float get_gradient_in_time_buffer(int site, int time){ float value; if (state.time_buffer[site][time] != MIN_CONTENTRATION) {value = ceil((state.time_buffer[site][time]-((float)MIN_CONTENTRATION))/gradientMapping.delta);} else{value = 1;} return value; } // 打印颜色渐变状态 --- Print color-gradient function void print_gradient(void){ // 根据状态变量计算梯度值 --- Calculate gradient value from state variable float value; // 代 --- generations printf("[color value:\t"); // 最左边3个格点的状态 --- state of the 3 left-most lattice sites for (int i = 0; i < 3;i++){ printf("%d ", (int) get_gradient_at_location(i)); printf("\t"); } printf("...\t"); // 三个中心格点的状态 --- state of the 3 center lattice sites for (int i = floor(N/2)-1 ; i < floor(N/2)+2;i++){ printf("%d ", (int) get_gradient_at_location(i)); printf("\t"); } printf("...\t"); // 3个最右边格点的状态 --- state of the 3 right-most lattice sites for (int i = N-3; i < N;i++){ printf("%d ", (int) get_gradient_at_location(i)); printf("\t"); } printf("\n"); } // 打印功能 --- Print function (truncated) void print_grid(void){ // 代 --- generations printf("[dt x %d]\t", state.generation_time); // 最左边3个格点的状态 --- state of the 3 left-most lattice sites for (int i = 0; i < 3;i++){ printf("%.2f ", state.u[i]); printf("\t"); } printf("...\t"); // 三个中心格点的状态 --- state of the 3 center lattice sites for (int i = floor(N/2)-1 ; i < floor(N/2)+2;i++){ printf("%.2f ", state.u[i]); printf("\t"); } printf("...\t"); // 3个最右边格点的状态 --- state of the 3 right-most lattice sites for (int i = N-3; i < N;i++){ printf("%.2f ", state.u[i]); printf("\t"); } printf("\n"); } // 推送时间缓冲 --- Push time buffer void push_time_buffer(void){ if (state.generation_time < (int)Y_SIZE) { for (int i=0; i < (int)X_SIZE; i++) state.time_buffer[i][state.generation_time]=state.u[i]; }else{ // for (int i=0; i < (int)X_SIZE; i++) state.time_buffer[i][state.generation_time%(int)Y_SIZE]=state.u[i]; for (int t = 0; t < ((int)Y_SIZE-1); t++) for (int i = 0; i <(int)X_SIZE; i++) state.time_buffer[i][t]=state.time_buffer[i][t+1] ; for (int i = 0; i <(int)X_SIZE; i++) state.time_buffer[i][(int)Y_SIZE-1]= state.u[i]; } } // 初始化功能 --- Initialization function static void on_button_init_lattice(GtkWidget *widget, gpointer data){ // 初始化浓度分布 --- Initialize concentration distribution for (int i = 0; i < N; i++) { if (i >= 45*N/100 && i <= 55*N/100) { state.u[i] = (float) MAX_CONCENTRATION; } else { state.u[i] = 0.0; } } //for (int i = 0; i < N; i++) state.time_buffer[i][0]= state.u[i]; state.initialized = TRUE; // 初始化时间 --- Initialize time state.generation_time = 0; push_time_buffer(); paint_time_buffer (data); state.initialized = TRUE; g_print ("Lattice initialized\n"); } void init_simulation_App(void){ state.running = FALSE; state.initialized = FALSE; // prepare color gradient and its mapping to state variiable // 制作颜色渐变 --- Make a color gradient color = make_color_gradient((int) N_GRADIENT_POINTS); // 根据状态变量计算梯度值 --- Calculate gradient value from state variable gradientMapping = make_state_gradient_map(); // Initialize time buffer for (int t = 0; t < T; t++) for (int i = 0; i < N; i++) state.time_buffer[i][t]=0.0; } // 更新功能 --- Update function (to increment one iteration/generation) void update_lattice(gpointer data){ // u_new: 为下一个时刻的浓度分布 double u_new[N];// --- To store the concentration distribution at the next moment // 强制边界条件 --- Enforce boundary condition u_new[0] = state.u[0]; u_new[N] = state.u[N]; // 内部节点计算 --- Internal node calculation (FTCS) for (int i = 1; i < N; i++) { u_new[i] = state.u[i] + (double)diffusion_rate * dt / (dx*dx) * (state.u[i+1] - 2*state.u[i] + state.u[i-1]); } // 更新浓度分布 --- Update concentration distribution for (int i = 0; i < N; i++) { state.u[i] = u_new[i]; } state.generation_time ++; print_grid(); print_gradient(); push_time_buffer(); paint_time_buffer (data); } /* Time handler to connect update function to the gtk loop */ gboolean time_handler (gpointer data) { update_lattice (data); return TRUE; } // 应用程序数据初始化应用程序数据初始化 --- application data initialization void set_up_simulation_environment(void){ // 初始化模拟 --- Initialize simulation init_simulation_App(); print_grid(); print_gradient(); g_print ("Application data initialized\n"); } // Control call_back functions /* Callback to start simulation */ static void on_button_start_simulation (GtkWidget *button, gpointer data) { if(!state.running && state.initialized) { state.run_id = g_idle_add ((GSourceFunc) time_handler, GTK_IMAGE (data)); state.running = TRUE; g_print ("Simulation started\n"); } } static void on_button_stop_simulation (GtkWidget *button, gpointer data) { if (state.running) { g_source_remove (state.run_id); state.running = FALSE; g_print ("Simulation stopped\n"); } } static void on_button_show_about(GtkWidget *widget, gpointer data) { GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file("X-Institute_logo_small.tif", NULL); GtkWidget *dialog = gtk_about_dialog_new(); gtk_about_dialog_set_program_name (GTK_ABOUT_DIALOG(dialog), "Diffusion PDE, a Gtk simulation"); gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(dialog), "version 0.0, 2024"); gtk_about_dialog_set_copyright(GTK_ABOUT_DIALOG(dialog),"Open Source Code"); gtk_about_dialog_set_comments(GTK_ABOUT_DIALOG(dialog), "Integrating the Diffusion PDE (FTCS)\n\nby: 许跃川 & 纪胡安"); gtk_about_dialog_set_website(GTK_ABOUT_DIALOG(dialog), "https://git.xinstitute.org.cn/keymer/Diffusion"); gtk_about_dialog_set_logo(GTK_ABOUT_DIALOG(dialog), pixbuf); g_object_unref(pixbuf), pixbuf = NULL; gtk_dialog_run(GTK_DIALOG (dialog)); gtk_widget_destroy(dialog); } // 激活Gtk功能 --- Activate Gtk function static void activate (GtkApplication *app, gpointer user_data){ // note this function is meant to only contain Gtk stuff set_up_simulation_environment(); // a bit of cheating // 声明小工具 --- declare Widgets GtkWidget *window, *grid, *image_space_time_concentration; // Gdk Pixel bufer to create an image GdkPixbuf *pixbuf; // 创建Gtk网格 --- Create a Gtk grid grid = gtk_grid_new (); // 创建新窗口 --- Create a new WINDOW window = gtk_application_window_new (app); // 设置窗口标题 --- Set window title gtk_window_set_title (GTK_WINDOW (window), "Diffusion (FTCS)"); // 使窗口不可调整大小 --- Make window not resizable gtk_window_set_resizable (GTK_WINDOW(window), FALSE); // 创建像素缓冲区 --- Create Pixel buffer pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, 0, 8, X_SIZE, Y_SIZE); // 从像素缓冲区创建图像 --- Create Image from empty Pixel buffer image_space_time_concentration = gtk_image_new_from_pixbuf(pixbuf); // 绘制图像 --- Paint Image (use time-buffer data) paint_time_buffer(image_space_time_concentration); //将图像添加到网格 --- Add Image to grid container gtk_grid_attach (GTK_GRID (grid), image_space_time_concentration, 0, 7, 5, 1); // 模拟控制 --- Simulation Control GtkWidget *button, *ctrl_frame, *button_box; button_box = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL); ctrl_frame = gtk_frame_new ("Simulation Control"); // Initialize button = gtk_button_new_with_label ("Init"); g_signal_connect (button, "clicked", G_CALLBACK (on_button_init_lattice), GTK_IMAGE (image_space_time_concentration)); gtk_container_add (GTK_CONTAINER (button_box), button); // Start button = gtk_button_new_with_label ("Start"); g_signal_connect (button, "clicked", G_CALLBACK (on_button_start_simulation), GTK_IMAGE (image_space_time_concentration)); gtk_container_add (GTK_CONTAINER (button_box), button); // Stop button = gtk_button_new_with_label ("Stop"); g_signal_connect (button, "clicked", G_CALLBACK (on_button_stop_simulation), NULL); gtk_container_add (GTK_CONTAINER (button_box), button); // About button = gtk_button_new_with_label ("About"); g_signal_connect (button, "clicked", G_CALLBACK (on_button_show_about), NULL); gtk_container_add (GTK_CONTAINER (button_box), button); // Quit button = gtk_button_new_with_label ("Quit"); g_signal_connect (button, "clicked", G_CALLBACK (on_button_stop_simulation), NULL); g_signal_connect_swapped (button, "clicked", G_CALLBACK (gtk_widget_destroy), window); gtk_container_add (GTK_CONTAINER (button_box), button); gtk_container_add (GTK_CONTAINER (ctrl_frame), button_box); gtk_grid_attach (GTK_GRID (grid), ctrl_frame, 0, 8, 5, 1); // 将网格添加到窗口 --- Add grid to the window gtk_container_add (GTK_CONTAINER (window), grid); // 显示窗口及其小工具 --- Show the window and its Widgets gtk_widget_show_all (window); } // 主要功能 --- Main function int main(int argc, char **argv){ GtkApplication *app; int status; app = gtk_application_new ("keymer.lab.yuechuan.diffusion.FTCS", G_APPLICATION_FLAGS_NONE); g_signal_connect (app, "activate", G_CALLBACK (activate), NULL); status = g_application_run (G_APPLICATION (app), argc, argv); g_object_unref (app); return status; } static void paint_time_buffer (gpointer data){ // 创建像素缓冲区 --- Create Pixel buffer GdkPixbuf *p; float value; p = gdk_pixbuf_new (GDK_COLORSPACE_RGB, 0, 8, X_SIZE, Y_SIZE); // 绘制(使用put_pixel) --- Paint (using put_pixel) int x,y, site, time; for (site = 0; site < X_SIZE; site++) // 空间 --- Space { for (time = 0; time < Y_SIZE; time++) // 时间 --- Time { // 从状态获取梯度值 --- get gradient value from state value = get_gradient_in_time_buffer(site,time); // 油漆 --- paint x = site; y = time; put_pixel (p, (int) x, (int) y, (guchar) color.red[(int)value], (guchar) color.green[(int)value], (guchar) color.blue[(int)value], 255); } } // 从缓冲区创建图像 --- Create image (data) from buffer gtk_image_set_from_pixbuf (GTK_IMAGE (data), GDK_PIXBUF (p)); // 释放缓冲存储器 --- Release buffer memory g_object_unref (p); }; // put_pixel的实现 --- Implementation of put_pixel. // Thanks to code from: // https://developer.gnome.org/gdk-pixbuf/stable/gdk-pixbuf-The-GdkPixbuf-Structure.html void put_pixel(GdkPixbuf *pixbuf, int x, int y, guchar red, guchar green, guchar blue, guchar alpha){ guchar *pixels, *p; int rowstride, numchannels; numchannels = gdk_pixbuf_get_n_channels(pixbuf); rowstride = gdk_pixbuf_get_rowstride(pixbuf); pixels = gdk_pixbuf_get_pixels(pixbuf); p = pixels + y * rowstride + x * numchannels; p[0] = red; p[1] = green; p[2] = blue; p[3] = alpha; }