From 60df2cacea2bbbb47f7f1b6e8bed7c9c82b9f85c Mon Sep 17 00:00:00 2001 From: thivin Date: Wed, 24 Apr 2024 09:22:21 +0530 Subject: [PATCH] Added Examples Examples are widely split into forward-problems and inverse problems Forwward Problems has examples with both complex and uniform geometries PDE's : CD2D, Poisson2D and Helmholtz2D are the examples. --- .../complex_mesh/cd2d/cd2d_example.py | 80 + .../complex_mesh/cd2d/input.yaml | 75 + .../complex_mesh/cd2d/main_cd2d.py | 309 +++ .../complex_mesh/cd2d/utility.py | 113 + .../helmholtz/helmholtz_example.py | 83 + .../complex_mesh/helmholtz/input.yaml | 75 + .../complex_mesh/helmholtz/main_helmholtz.py | 307 +++ .../complex_mesh/helmholtz/utility.py | 113 + .../complex_mesh/meshes/circle_quad.mesh | 2252 +++++++++++++++++ .../complex_mesh/poisson_2d/input.yaml | 75 + .../complex_mesh/poisson_2d/main_poisson2d.py | 309 +++ .../complex_mesh/poisson_2d/sin_cos.py | 93 + .../complex_mesh/poisson_2d/utility.py | 113 + .../helmholtz_2d/helmholtz_example.py | 83 + .../uniform_mesh/helmholtz_2d/input.yaml | 75 + .../helmholtz_2d/main_helmholtz.py | 316 +++ .../uniform_mesh/helmholtz_2d/utility.py | 113 + .../uniform_mesh/poisson_2d/input.yaml | 75 + .../uniform_mesh/poisson_2d/main_poisson2d.py | 316 +++ .../uniform_mesh/poisson_2d/sin_cos.py | 85 + .../uniform_mesh/poisson_2d/utility.py | 113 + 21 files changed, 5173 insertions(+) create mode 100644 examples/forward_problems_2d/complex_mesh/cd2d/cd2d_example.py create mode 100644 examples/forward_problems_2d/complex_mesh/cd2d/input.yaml create mode 100644 examples/forward_problems_2d/complex_mesh/cd2d/main_cd2d.py create mode 100644 examples/forward_problems_2d/complex_mesh/cd2d/utility.py create mode 100644 examples/forward_problems_2d/complex_mesh/helmholtz/helmholtz_example.py create mode 100644 examples/forward_problems_2d/complex_mesh/helmholtz/input.yaml create mode 100644 examples/forward_problems_2d/complex_mesh/helmholtz/main_helmholtz.py create mode 100644 examples/forward_problems_2d/complex_mesh/helmholtz/utility.py create mode 100644 examples/forward_problems_2d/complex_mesh/meshes/circle_quad.mesh create mode 100644 examples/forward_problems_2d/complex_mesh/poisson_2d/input.yaml create mode 100644 examples/forward_problems_2d/complex_mesh/poisson_2d/main_poisson2d.py create mode 100644 examples/forward_problems_2d/complex_mesh/poisson_2d/sin_cos.py create mode 100644 examples/forward_problems_2d/complex_mesh/poisson_2d/utility.py create mode 100644 examples/forward_problems_2d/uniform_mesh/helmholtz_2d/helmholtz_example.py create mode 100644 examples/forward_problems_2d/uniform_mesh/helmholtz_2d/input.yaml create mode 100644 examples/forward_problems_2d/uniform_mesh/helmholtz_2d/main_helmholtz.py create mode 100644 examples/forward_problems_2d/uniform_mesh/helmholtz_2d/utility.py create mode 100644 examples/forward_problems_2d/uniform_mesh/poisson_2d/input.yaml create mode 100644 examples/forward_problems_2d/uniform_mesh/poisson_2d/main_poisson2d.py create mode 100644 examples/forward_problems_2d/uniform_mesh/poisson_2d/sin_cos.py create mode 100644 examples/forward_problems_2d/uniform_mesh/poisson_2d/utility.py diff --git a/examples/forward_problems_2d/complex_mesh/cd2d/cd2d_example.py b/examples/forward_problems_2d/complex_mesh/cd2d/cd2d_example.py new file mode 100644 index 0000000..d612c41 --- /dev/null +++ b/examples/forward_problems_2d/complex_mesh/cd2d/cd2d_example.py @@ -0,0 +1,80 @@ +# Example file for the poisson problem +# Path: examples/poisson.py +# file contains the exact solution, rhs and boundary conditions for the poisson problem +import numpy as np +import tensorflow as tf + + +def left_boundary(x, y): + """ + This function will return the boundary value for given component of a boundary + """ + return 0.0 + + +def right_boundary(x, y): + """ + This function will return the boundary value for given component of a boundary + """ + val = 0.0 + return val + + +def top_boundary(x, y): + """ + This function will return the boundary value for given component of a boundary + """ + val = 0.0 + return np.ones_like(x) * val + + +def bottom_boundary(x, y): + """ + This function will return the boundary value for given component of a boundary + """ + return 0.0 + + +def rhs(x, y): + """ + This function will return the value of the rhs at a given point + """ + f_temp = 32 * (x * (1 - x) + y * (1 - y)) + + return f_temp + + +def exact_solution(x, y): + """ + This function will return the exact solution at a given point + """ + + val = 16 * x * (1 - x) * y * (1 - y) + + return val + + +def get_boundary_function_dict(): + """ + This function will return a dictionary of boundary functions + """ + return {1000: bottom_boundary, 1001: right_boundary, 1002: top_boundary, 1003: left_boundary} + + +def get_bound_cond_dict(): + """ + This function will return a dictionary of boundary conditions + """ + return {1000: "dirichlet", 1001: "dirichlet", 1002: "dirichlet", 1003: "dirichlet"} + + +def get_bilinear_params_dict(): + """ + This function will return a dictionary of bilinear parameters + """ + eps = 1.0 + b_x = 1.0 + b_y = 0.0 + c = 0.0 + + return {"eps": eps, "b_x": b_x, "b_y": b_y, "c": c} diff --git a/examples/forward_problems_2d/complex_mesh/cd2d/input.yaml b/examples/forward_problems_2d/complex_mesh/cd2d/input.yaml new file mode 100644 index 0000000..57deeb8 --- /dev/null +++ b/examples/forward_problems_2d/complex_mesh/cd2d/input.yaml @@ -0,0 +1,75 @@ +# This YAML file contains configuration parameters for a variational physics-informed neural network (VarPINN) experimentation. + +experimentation: + output_path: "output/cd2d/1" # Path to the output directory where the results will be saved. + +geometry: + mesh_generation_method: "external" # Method for generating the mesh. Can be "internal" or "external". + generate_mesh_plot: True # Flag indicating whether to generate a plot of the mesh. + + # internal mesh generated quadrilateral mesh, depending on the parameters specified below. + + internal_mesh_params: # Parameters for internal mesh generation method. + x_min: 0 # Minimum x-coordinate of the domain. + x_max: 1 # Maximum x-coordinate of the domain. + y_min: 0 # Minimum y-coordinate of the domain. + y_max: 1 # Maximum y-coordinate of the domain. + n_cells_x: 4 # Number of cells in the x-direction. + n_cells_y: 4 # Number of cells in the y-direction. + n_boundary_points: 400 # Number of boundary points. + n_test_points_x: 100 # Number of test points in the x-direction. + n_test_points_y: 100 # Number of test points in the y-direction. + + exact_solution: + exact_solution_generation: "external" # whether the exact solution needs to be read from external file. + exact_solution_file_name: "" # External solution file name. + + mesh_type: "quadrilateral" # Type of mesh. Can be "quadrilateral" or other supported types. + + external_mesh_params: # Parameters for external mesh generation method. + mesh_file_name: "../meshes/circle_quad.mesh" # Path to the external mesh file (should be a .mesh file). + boundary_refinement_level: 4 # Level of refinement for the boundary. + boundary_sampling_method: "lhs" # Method for sampling the boundary. Can be "uniform" or "lhs". + +fe: + fe_order: 6 # Order of the finite element basis functions. + fe_type: "legendre" # Type of finite element basis functions. Can be "jacobi" or other supported types. + quad_order: 10 # Order of the quadrature rule. + quad_type: "gauss-jacobi" # Type of quadrature rule. Can be "gauss-jacobi" or other supported types. + +pde: + beta: 10 # Parameter for the PDE. + +model: + model_architecture: [2, 50,50,50,50, 1] # Architecture of the neural network model. + activation: "tanh" # Activation function used in the neural network. + use_attention: False # Flag indicating whether to use attention mechanism in the model. + epochs: 50000 # Number of training epochs. + dtype: "float32" # Data type used for computations. + set_memory_growth: False # Flag indicating whether to set memory growth for GPU. + + learning_rate: # Parameters for learning rate scheduling. + initial_learning_rate: 0.001 # Initial learning rate. + use_lr_scheduler: False # Flag indicating whether to use learning rate scheduler. + decay_steps: 1000 # Number of steps between each learning rate decay. + decay_rate: 0.99 # Decay rate for the learning rate. + staircase: False # Flag indicating whether to use staircase decay. + + +logging: + update_progress_bar: 100 # Number of steps between each update of the progress bar. + update_console_output: 5000 # Number of steps between each update of the console output. + update_solution_images: 10000 # Number of steps between each update of the intermediate solution images. + plot_residual_images: True + test_error_last_n_epochs: 1000 + +wandb: + use_wandb: False # Flag indicating whether to use Weights & Biases for logging. + project_name: "Volker_example_2" # Name of the Weights & Biases project. + wandb_run_prefix: "without_scaling" # Prefix for the Weights & Biases run. + entity: "starslab-iisc" # Weights & Biases entity. + +additional: + run_by: "Thivin" # Name of the person running the experiment. + System: "24" # System identifier. + diff --git a/examples/forward_problems_2d/complex_mesh/cd2d/main_cd2d.py b/examples/forward_problems_2d/complex_mesh/cd2d/main_cd2d.py new file mode 100644 index 0000000..49c3dc8 --- /dev/null +++ b/examples/forward_problems_2d/complex_mesh/cd2d/main_cd2d.py @@ -0,0 +1,309 @@ +import numpy as np +import pandas as pd +import pytest +import tensorflow as tf +from pathlib import Path +from tqdm import tqdm +import yaml +import sys +import copy +from tensorflow.keras import layers +from tensorflow.keras import initializers +from rich.console import Console +import copy +import time + + +from fastvpinns.Geometry.geometry_2d import Geometry_2D +from fastvpinns.FE_2D.fespace2d import Fespace2D +from fastvpinns.data.datahandler2d import DataHandler2D +from fastvpinns.model.model import DenseModel +from fastvpinns.physics.cd2d import pde_loss_cd2d +from fastvpinns.utils.plot_utils import plot_contour, plot_loss_function, plot_test_loss_function +from fastvpinns.utils.compute_utils import compute_errors_combined +from fastvpinns.utils.print_utils import print_table + +# import the example file +from cd2d_example import * + +# import all files from utility +from utility import * + +if __name__ == "__main__": + + console = Console() + + # check input arguments + if len(sys.argv) != 2: + print("Usage: python main.py ") + sys.exit(1) + + # Read the YAML file + with open(sys.argv[1], 'r') as f: + config = yaml.safe_load(f) + + # Extract the values from the YAML file + i_output_path = config['experimentation']['output_path'] + + i_mesh_generation_method = config['geometry']['mesh_generation_method'] + i_generate_mesh_plot = config['geometry']['generate_mesh_plot'] + i_mesh_type = config['geometry']['mesh_type'] + i_x_min = config['geometry']['internal_mesh_params']['x_min'] + i_x_max = config['geometry']['internal_mesh_params']['x_max'] + i_y_min = config['geometry']['internal_mesh_params']['y_min'] + i_y_max = config['geometry']['internal_mesh_params']['y_max'] + i_n_cells_x = config['geometry']['internal_mesh_params']['n_cells_x'] + i_n_cells_y = config['geometry']['internal_mesh_params']['n_cells_y'] + i_n_boundary_points = config['geometry']['internal_mesh_params']['n_boundary_points'] + i_n_test_points_x = config['geometry']['internal_mesh_params']['n_test_points_x'] + i_n_test_points_y = config['geometry']['internal_mesh_params']['n_test_points_y'] + i_exact_solution_generation = config['geometry']['exact_solution']['exact_solution_generation'] + i_exact_solution_file_name = config['geometry']['exact_solution']['exact_solution_file_name'] + + i_mesh_file_name = config['geometry']['external_mesh_params']['mesh_file_name'] + i_boundary_refinement_level = config['geometry']['external_mesh_params'][ + 'boundary_refinement_level' + ] + i_boundary_sampling_method = config['geometry']['external_mesh_params'][ + 'boundary_sampling_method' + ] + + i_fe_order = config['fe']['fe_order'] + i_fe_type = config['fe']['fe_type'] + i_quad_order = config['fe']['quad_order'] + i_quad_type = config['fe']['quad_type'] + + i_model_architecture = config['model']['model_architecture'] + i_activation = config['model']['activation'] + i_use_attention = config['model']['use_attention'] + i_epochs = config['model']['epochs'] + i_dtype = config['model']['dtype'] + if i_dtype == "float64": + i_dtype = tf.float64 + elif i_dtype == "float32": + i_dtype = tf.float32 + else: + print("[ERROR] The given dtype is not a valid tensorflow dtype") + raise ValueError("The given dtype is not a valid tensorflow dtype") + + i_set_memory_growth = config['model']['set_memory_growth'] + i_learning_rate_dict = config['model']['learning_rate'] + + i_beta = config['pde']['beta'] + + i_update_progress_bar = config['logging']['update_progress_bar'] + i_update_console_output = config['logging']['update_console_output'] + i_update_solution_images = config['logging']['update_solution_images'] + + # use pathlib to create the folder,if it does not exist + folder = Path(i_output_path) + # create the folder if it does not exist + if not folder.exists(): + folder.mkdir(parents=True, exist_ok=True) + + # get the boundary function dictionary from example file + bound_function_dict, bound_condition_dict = get_boundary_function_dict(), get_bound_cond_dict() + + # Initiate a Geometry_2D object + domain = Geometry_2D( + i_mesh_type, i_mesh_generation_method, i_n_test_points_x, i_n_test_points_y, i_output_path + ) + + # load the mesh + # cells, boundary_points = domain.generate_quad_mesh_internal(x_limits = [i_x_min, i_x_max], \ + # y_limits = [i_y_min, i_y_max], \ + # n_cells_x = i_n_cells_x, \ + # n_cells_y = i_n_cells_y, \ + # num_boundary_points=i_n_boundary_points) + + cells, boundary_points = domain.read_mesh( + i_mesh_file_name, + i_boundary_refinement_level, + i_boundary_sampling_method, + refinement_level=1, + ) + + # get the boundary function dictionary from example file + bound_function_dict, bound_condition_dict = get_boundary_function_dict(), get_bound_cond_dict() + + fespace = Fespace2D( + mesh=domain.mesh, + cells=cells, + boundary_points=boundary_points, + cell_type=domain.mesh_type, + fe_order=i_fe_order, + fe_type=i_fe_type, + quad_order=i_quad_order, + quad_type=i_quad_type, + fe_transformation_type="bilinear", + bound_function_dict=bound_function_dict, + bound_condition_dict=bound_condition_dict, + forcing_function=rhs, + output_path=i_output_path, + generate_mesh_plot=i_generate_mesh_plot, + ) + + # instantiate data handler + datahandler = DataHandler2D(fespace, domain, dtype=i_dtype) + + params_dict = {} + params_dict['n_cells'] = fespace.n_cells + + # get the input data for the PDE + train_dirichlet_input, train_dirichlet_output = datahandler.get_dirichlet_input() + + # get bilinear parameters + # this function will obtain the values of the bilinear parameters from the model + # and convert them into tensors of desired dtype + bilinear_params_dict = datahandler.get_bilinear_params_dict_as_tensors(get_bilinear_params_dict) + + model = DenseModel( + layer_dims=[2, 30, 30, 30, 1], + learning_rate_dict=i_learning_rate_dict, + params_dict=params_dict, + loss_function=pde_loss_cd2d, + input_tensors_list=[datahandler.x_pde_list, train_dirichlet_input, train_dirichlet_output], + orig_factor_matrices=[ + datahandler.shape_val_mat_list, + datahandler.grad_x_mat_list, + datahandler.grad_y_mat_list, + ], + force_function_list=datahandler.forcing_function_list, + tensor_dtype=i_dtype, + use_attention=i_use_attention, + activation=i_activation, + hessian=False, + ) + + test_points = domain.get_test_points() + print(f"[bold]Number of Test Points = [/bold] {test_points.shape[0]}") + y_exact = exact_solution(test_points[:, 0], test_points[:, 1]) + + # plot the exact solution + num_epochs = i_epochs # num_epochs + progress_bar = tqdm( + total=num_epochs, + desc='Training', + unit='epoch', + bar_format="{l_bar}{bar:40}{r_bar}{bar:-10b}", + colour="green", + ncols=100, + ) + loss_array = [] # total loss + test_loss_array = [] # test loss + time_array = [] # time per epoc + # beta - boundary loss parameters + beta = tf.constant(i_beta, dtype=i_dtype) + + # ---------------------------------------------------------------# + # ------------- TRAINING LOOP ---------------------------------- # + # ---------------------------------------------------------------# + for epoch in range(num_epochs): + + # Train the model + batch_start_time = time.time() + loss = model.train_step(beta=beta, bilinear_params_dict=bilinear_params_dict) + elapsed = time.time() - batch_start_time + + # print(elapsed) + time_array.append(elapsed) + + loss_array.append(loss['loss']) + + # ------ Intermediate results update ------ # + if (epoch + 1) % i_update_console_output == 0 or epoch == num_epochs - 1: + y_pred = model(test_points).numpy() + y_pred = y_pred.reshape(-1) + + error = np.abs(y_exact - y_pred) + + # get errors + ( + l2_error, + linf_error, + l2_error_relative, + linf_error_relative, + l1_error, + l1_error_relative, + ) = compute_errors_combined(y_exact, y_pred) + + loss_pde = float(loss['loss_pde'].numpy()) + loss_dirichlet = float(loss['loss_dirichlet'].numpy()) + total_loss = float(loss['loss'].numpy()) + + # Append test loss + test_loss_array.append(l1_error) + + solution_array = np.c_[y_pred, y_exact, np.abs(y_exact - y_pred)] + domain.write_vtk( + solution_array, + output_path=i_output_path, + filename=f"prediction_{epoch+1}.vtk", + data_names=["Sol", "Exact", "Error"], + ) + + console.print(f"\nEpoch [bold]{epoch+1}/{num_epochs}[/bold]") + console.print("[bold]--------------------[/bold]") + console.print("[bold]Beta : [/bold]", beta.numpy(), end=" ") + console.print( + f"Variational Losses || Pde Loss : [red]{loss_pde:.3e}[/red] Dirichlet Loss : [red]{loss_dirichlet:.3e}[/red] Total Loss : [red]{total_loss:.3e}[/red]" + ) + console.print( + f"Test Losses || L1 Error : {l1_error:.3e} L2 Error : {l2_error:.3e} Linf Error : {linf_error:.3e}" + ) + + progress_bar.update(1) + + # Save the model + model.save_weights(str(Path(i_output_path) / "model_weights")) + + solution_array = np.c_[y_pred, y_exact, np.abs(y_exact - y_pred)] + domain.write_vtk( + solution_array, + output_path=i_output_path, + filename=f"prediction_{epoch+1}.vtk", + data_names=["Sol", "Exact", "Error"], + ) + # print the Error values in table + print_table( + "Error Values", + ["Error Type", "Value"], + [ + "L2 Error", + "Linf Error", + "Relative L2 Error", + "Relative Linf Error", + "L1 Error", + "Relative L1 Error", + ], + [l2_error, linf_error, l2_error_relative, linf_error_relative, l1_error, l1_error_relative], + ) + + # print the time values in table + print_table( + "Time Values", + ["Time Type", "Value"], + [ + "Time per Epoch(s) - Median", + "Time per Epoch(s) IQR-25% ", + "Time per Epoch(s) IQR-75% ", + "Mean (s)", + "Epochs per second", + "Total Train Time", + ], + [ + np.median(time_array), + np.percentile(time_array, 25), + np.percentile(time_array, 75), + np.mean(time_array), + int(i_epochs / np.sum(time_array)), + np.sum(time_array), + ], + ) + + # save all the arrays as numpy arrays + np.savetxt(str(Path(i_output_path) / "loss_function.txt"), np.array(loss_array)) + np.savetxt(str(Path(i_output_path) / "prediction.txt"), y_pred) + np.savetxt(str(Path(i_output_path) / "exact.txt"), y_exact) + np.savetxt(str(Path(i_output_path) / "error.txt"), error) + np.savetxt(str(Path(i_output_path) / "time_per_epoch.txt"), np.array(time_array)) diff --git a/examples/forward_problems_2d/complex_mesh/cd2d/utility.py b/examples/forward_problems_2d/complex_mesh/cd2d/utility.py new file mode 100644 index 0000000..794a0ea --- /dev/null +++ b/examples/forward_problems_2d/complex_mesh/cd2d/utility.py @@ -0,0 +1,113 @@ +import sys +import yaml +import numpy as np + +from fastvpinns.utils.plot_utils import plot_contour, plot_loss_function, plot_test_loss_function +from fastvpinns.utils.compute_utils import compute_errors_combined + + +def get_errors( + model, + console, + y_pred, + y_exact, + Y_Exact_Matrix, + i_n_test_points_x, + i_n_test_points_y, + i_output_path, + epoch, + loss, + num_epochs, +): + """ + Calculate and return various error metrics and loss values. + + Args: + model (object): The trained model. + console (object): The console object for printing messages. + y_exact (array): The exact solution. + Y_Exact_Matrix (array): The matrix of exact solutions. + i_n_test_points_x (int): The number of test points in the x-direction. + i_n_test_points_y (int): The number of test points in the y-direction. + i_output_path (str): The output path for saving plots. + epoch (int): The current epoch number. + loss (dict): The dictionary containing different loss values. + num_epochs (int): The total number of epochs. + + Returns: + dict: A dictionary containing various error metrics and loss values. + """ + + # Compute error metrics + l2_error, linf_error, l2_error_relative, linf_error_relative, l1_error, l1_error_relative = ( + compute_errors_combined(y_exact, y_pred) + ) + + # Print epoch information + console.print(f"\nEpoch [bold]{epoch+1}/{num_epochs}[/bold]") + console.print("[bold]--------------------[/bold]") + console.print( + f"Variational Losses || Pde Loss : [red]{loss_pde:.3e}[/red] Dirichlet Loss : [red]{loss_dirichlet:.3e}[/red] Total Loss : [red]{total_loss:.3e}[/red]" + ) + console.print(f"Test Losses || L1 Error : {l1_error:.3e}", end=" ") + console.print(f"L2 Error : {l2_error:.3e}", end=" ") + console.print(f"Linf Error : {linf_error:.3e}", end="\n") + + return { + 'l2_error': l2_error, + 'linf_error': linf_error, + 'l2_error_relative': l2_error_relative, + 'linf_error_relative': linf_error_relative, + 'l1_error': l1_error, + 'l1_error_relative': l1_error_relative, + 'loss_pde': loss_pde, + 'loss_dirichlet': loss_dirichlet, + 'total_loss': total_loss, + } + + +def plot_results( + loss_array, + test_loss_array, + y_pred, + X, + Y, + Y_Exact_Matrix, + i_output_path, + epoch, + i_n_test_points_x, + i_n_test_points_y, +): + """ + Plot the loss function, test loss function, solution, and error. + + Args: + loss_array (array): Array of loss values during training. + test_loss_array (array): Array of test loss values during training. + y_pred (array): Predicted solution. + X (array): X-coordinates of the grid. + Y (array): Y-coordinates of the grid. + Y_Exact_Matrix (array): Matrix of exact solutions. + i_output_path (str): Output path for saving plots. + epoch (int): Current epoch number. + i_n_test_points_x (int): Number of test points in the x-direction. + i_n_test_points_y (int): Number of test points in the y-direction. + """ + # plot loss + plot_loss_function(loss_array, i_output_path) # plots NN loss + plot_test_loss_function(test_loss_array, i_output_path) # plots test loss + + # plot solution + y_pred = y_pred.reshape(i_n_test_points_x, i_n_test_points_y) + error = np.abs(Y_Exact_Matrix - y_pred) + plot_contour( + x=X, + y=Y, + z=y_pred, + output_path=i_output_path, + filename=f"prediction_{epoch+1}", + title="Prediction", + ) + plot_contour( + x=X, y=Y, z=error, output_path=i_output_path, filename=f"error_{epoch+1}", title="Error" + ) diff --git a/examples/forward_problems_2d/complex_mesh/helmholtz/helmholtz_example.py b/examples/forward_problems_2d/complex_mesh/helmholtz/helmholtz_example.py new file mode 100644 index 0000000..0899265 --- /dev/null +++ b/examples/forward_problems_2d/complex_mesh/helmholtz/helmholtz_example.py @@ -0,0 +1,83 @@ +# Example file for the poisson problem +# Path: examples/poisson.py +# file contains the exact solution, rhs and boundary conditions for the poisson problem +import numpy as np +import tensorflow as tf + + +def left_boundary(x, y): + """ + This function will return the boundary value for given component of a boundary + """ + return (x + y) * np.sin(np.pi * x) * np.sin(np.pi * y) + + +def right_boundary(x, y): + """ + This function will return the boundary value for given component of a boundary + """ + val = 0.0 + return (x + y) * np.sin(np.pi * x) * np.sin(np.pi * y) + + +def top_boundary(x, y): + """ + This function will return the boundary value for given component of a boundary + """ + val = 0.0 + return (x + y) * np.sin(np.pi * x) * np.sin(np.pi * y) + + +def bottom_boundary(x, y): + """ + This function will return the boundary value for given component of a boundary + """ + return (x + y) * np.sin(np.pi * x) * np.sin(np.pi * y) + + +def rhs(x, y): + """ + This function will return the value of the rhs at a given point + """ + # f_temp = 32 * (x * (1 - x) + y * (1 - y)) + # f_temp = 1 + + term1 = 2 * np.pi * np.cos(np.pi * y) * np.sin(np.pi * x) + term2 = 2 * np.pi * np.cos(np.pi * x) * np.sin(np.pi * y) + term3 = (x + y) * np.sin(np.pi * x) * np.sin(np.pi * y) + term4 = -2 * (np.pi**2) * (x + y) * np.sin(np.pi * x) * np.sin(np.pi * y) + + result = term1 + term2 + term3 + term4 + return result + + +def exact_solution(x, y): + """ + This function will return the exact solution at a given point + """ + + return (x + y) * np.sin(np.pi * x) * np.sin(np.pi * y) + + +def get_boundary_function_dict(): + """ + This function will return a dictionary of boundary functions + """ + return {1000: bottom_boundary, 1001: right_boundary, 1002: top_boundary, 1003: left_boundary} + + +def get_bound_cond_dict(): + """ + This function will return a dictionary of boundary conditions + """ + return {1000: "dirichlet", 1001: "dirichlet", 1002: "dirichlet", 1003: "dirichlet"} + + +def get_bilinear_params_dict(): + """ + This function will return a dictionary of bilinear parameters + """ + k = 1.0 + eps = 1.0 + + return {"k": k, "eps": eps} diff --git a/examples/forward_problems_2d/complex_mesh/helmholtz/input.yaml b/examples/forward_problems_2d/complex_mesh/helmholtz/input.yaml new file mode 100644 index 0000000..865b448 --- /dev/null +++ b/examples/forward_problems_2d/complex_mesh/helmholtz/input.yaml @@ -0,0 +1,75 @@ +# This YAML file contains configuration parameters for a variational physics-informed neural network (VarPINN) experimentation. + +experimentation: + output_path: "output/helmholtz/1" # Path to the output directory where the results will be saved. + +geometry: + mesh_generation_method: "external" # Method for generating the mesh. Can be "internal" or "external". + generate_mesh_plot: True # Flag indicating whether to generate a plot of the mesh. + + # internal mesh generated quadrilateral mesh, depending on the parameters specified below. + + internal_mesh_params: # Parameters for internal mesh generation method. + x_min: 0 # Minimum x-coordinate of the domain. + x_max: 1 # Maximum x-coordinate of the domain. + y_min: 0 # Minimum y-coordinate of the domain. + y_max: 1 # Maximum y-coordinate of the domain. + n_cells_x: 4 # Number of cells in the x-direction. + n_cells_y: 4 # Number of cells in the y-direction. + n_boundary_points: 400 # Number of boundary points. + n_test_points_x: 100 # Number of test points in the x-direction. + n_test_points_y: 100 # Number of test points in the y-direction. + + exact_solution: + exact_solution_generation: "externak" # whether the exact solution needs to be read from external file. + exact_solution_file_name: "" # External solution file name. + + mesh_type: "quadrilateral" # Type of mesh. Can be "quadrilateral" or other supported types. + + external_mesh_params: # Parameters for external mesh generation method. + mesh_file_name: "../meshes/circle_quad.mesh" # Path to the external mesh file (should be a .mesh file). + boundary_refinement_level: 4 # Level of refinement for the boundary. + boundary_sampling_method: "lhs" # Method for sampling the boundary. Can be "uniform" or "lhs". + +fe: + fe_order: 6 # Order of the finite element basis functions. + fe_type: "legendre" # Type of finite element basis functions. Can be "jacobi" or other supported types. + quad_order: 10 # Order of the quadrature rule. + quad_type: "gauss-jacobi" # Type of quadrature rule. Can be "gauss-jacobi" or other supported types. + +pde: + beta: 10 # Parameter for the PDE. + +model: + model_architecture: [2, 50,50,50,50, 1] # Architecture of the neural network model. + activation: "tanh" # Activation function used in the neural network. + use_attention: False # Flag indicating whether to use attention mechanism in the model. + epochs: 10000 # Number of training epochs. + dtype: "float32" # Data type used for computations. + set_memory_growth: False # Flag indicating whether to set memory growth for GPU. + + learning_rate: # Parameters for learning rate scheduling. + initial_learning_rate: 0.001 # Initial learning rate. + use_lr_scheduler: False # Flag indicating whether to use learning rate scheduler. + decay_steps: 1000 # Number of steps between each learning rate decay. + decay_rate: 0.99 # Decay rate for the learning rate. + staircase: False # Flag indicating whether to use staircase decay. + + +logging: + update_progress_bar: 100 # Number of steps between each update of the progress bar. + update_console_output: 5000 # Number of steps between each update of the console output. + update_solution_images: 10000 # Number of steps between each update of the intermediate solution images. + plot_residual_images: True + test_error_last_n_epochs: 1000 + +wandb: + use_wandb: False # Flag indicating whether to use Weights & Biases for logging. + project_name: "Volker_example_2" # Name of the Weights & Biases project. + wandb_run_prefix: "without_scaling" # Prefix for the Weights & Biases run. + entity: "starslab-iisc" # Weights & Biases entity. + +additional: + run_by: "Thivin" # Name of the person running the experiment. + System: "24" # System identifier. + diff --git a/examples/forward_problems_2d/complex_mesh/helmholtz/main_helmholtz.py b/examples/forward_problems_2d/complex_mesh/helmholtz/main_helmholtz.py new file mode 100644 index 0000000..64365e8 --- /dev/null +++ b/examples/forward_problems_2d/complex_mesh/helmholtz/main_helmholtz.py @@ -0,0 +1,307 @@ +import numpy as np +import pandas as pd +import pytest +import tensorflow as tf +from pathlib import Path +from tqdm import tqdm +import yaml +import sys +import copy +from tensorflow.keras import layers +from tensorflow.keras import initializers +from rich.console import Console +import copy +import time + + +from fastvpinns.Geometry.geometry_2d import Geometry_2D +from fastvpinns.FE_2D.fespace2d import Fespace2D +from fastvpinns.data.datahandler2d import DataHandler2D +from fastvpinns.model.model import DenseModel +from fastvpinns.physics.helmholtz2d import pde_loss_helmholtz +from fastvpinns.utils.plot_utils import plot_contour, plot_loss_function, plot_test_loss_function +from fastvpinns.utils.compute_utils import compute_errors_combined +from fastvpinns.utils.print_utils import print_table + +# import the example file +from helmholtz_example import * + +# import all files from utility +from utility import * + +if __name__ == "__main__": + + console = Console() + + # check input arguments + if len(sys.argv) != 2: + print("Usage: python main.py ") + sys.exit(1) + + # Read the YAML file + with open(sys.argv[1], 'r') as f: + config = yaml.safe_load(f) + + # Extract the values from the YAML file + i_output_path = config['experimentation']['output_path'] + + i_mesh_generation_method = config['geometry']['mesh_generation_method'] + i_generate_mesh_plot = config['geometry']['generate_mesh_plot'] + i_mesh_type = config['geometry']['mesh_type'] + i_x_min = config['geometry']['internal_mesh_params']['x_min'] + i_x_max = config['geometry']['internal_mesh_params']['x_max'] + i_y_min = config['geometry']['internal_mesh_params']['y_min'] + i_y_max = config['geometry']['internal_mesh_params']['y_max'] + i_n_cells_x = config['geometry']['internal_mesh_params']['n_cells_x'] + i_n_cells_y = config['geometry']['internal_mesh_params']['n_cells_y'] + i_n_boundary_points = config['geometry']['internal_mesh_params']['n_boundary_points'] + i_n_test_points_x = config['geometry']['internal_mesh_params']['n_test_points_x'] + i_n_test_points_y = config['geometry']['internal_mesh_params']['n_test_points_y'] + i_exact_solution_generation = config['geometry']['exact_solution']['exact_solution_generation'] + i_exact_solution_file_name = config['geometry']['exact_solution']['exact_solution_file_name'] + + i_mesh_file_name = config['geometry']['external_mesh_params']['mesh_file_name'] + i_boundary_refinement_level = config['geometry']['external_mesh_params'][ + 'boundary_refinement_level' + ] + i_boundary_sampling_method = config['geometry']['external_mesh_params'][ + 'boundary_sampling_method' + ] + + i_fe_order = config['fe']['fe_order'] + i_fe_type = config['fe']['fe_type'] + i_quad_order = config['fe']['quad_order'] + i_quad_type = config['fe']['quad_type'] + + i_model_architecture = config['model']['model_architecture'] + i_activation = config['model']['activation'] + i_use_attention = config['model']['use_attention'] + i_epochs = config['model']['epochs'] + i_dtype = config['model']['dtype'] + if i_dtype == "float64": + i_dtype = tf.float64 + elif i_dtype == "float32": + i_dtype = tf.float32 + else: + print("[ERROR] The given dtype is not a valid tensorflow dtype") + raise ValueError("The given dtype is not a valid tensorflow dtype") + + i_set_memory_growth = config['model']['set_memory_growth'] + i_learning_rate_dict = config['model']['learning_rate'] + + i_beta = config['pde']['beta'] + + i_update_progress_bar = config['logging']['update_progress_bar'] + i_update_console_output = config['logging']['update_console_output'] + i_update_solution_images = config['logging']['update_solution_images'] + + # use pathlib to create the folder,if it does not exist + folder = Path(i_output_path) + # create the folder if it does not exist + if not folder.exists(): + folder.mkdir(parents=True, exist_ok=True) + + # get the boundary function dictionary from example file + bound_function_dict, bound_condition_dict = get_boundary_function_dict(), get_bound_cond_dict() + + # Initiate a Geometry_2D object + domain = Geometry_2D( + i_mesh_type, i_mesh_generation_method, i_n_test_points_x, i_n_test_points_y, i_output_path + ) + + # load the mesh + # cells, boundary_points = domain.generate_quad_mesh_internal(x_limits = [i_x_min, i_x_max], \ + # y_limits = [i_y_min, i_y_max], \ + # n_cells_x = i_n_cells_x, \ + # n_cells_y = i_n_cells_y, \ + # num_boundary_points=i_n_boundary_points) + + cells, boundary_points = domain.read_mesh( + i_mesh_file_name, + i_boundary_refinement_level, + i_boundary_sampling_method, + refinement_level=1, + ) + # get the boundary function dictionary from example file + bound_function_dict, bound_condition_dict = get_boundary_function_dict(), get_bound_cond_dict() + + fespace = Fespace2D( + mesh=domain.mesh, + cells=cells, + boundary_points=boundary_points, + cell_type=domain.mesh_type, + fe_order=i_fe_order, + fe_type=i_fe_type, + quad_order=i_quad_order, + quad_type=i_quad_type, + fe_transformation_type="bilinear", + bound_function_dict=bound_function_dict, + bound_condition_dict=bound_condition_dict, + forcing_function=rhs, + output_path=i_output_path, + generate_mesh_plot=i_generate_mesh_plot, + ) + + # instantiate data handler + datahandler = DataHandler2D(fespace, domain, dtype=i_dtype) + + params_dict = {} + params_dict['n_cells'] = fespace.n_cells + + # get the input data for the PDE + train_dirichlet_input, train_dirichlet_output = datahandler.get_dirichlet_input() + + # get bilinear parameters + # this function will obtain the values of the bilinear parameters from the model + # and convert them into tensors of desired dtype + bilinear_params_dict = datahandler.get_bilinear_params_dict_as_tensors(get_bilinear_params_dict) + + model = DenseModel( + layer_dims=[2, 30, 30, 30, 1], + learning_rate_dict=i_learning_rate_dict, + params_dict=params_dict, + loss_function=pde_loss_helmholtz, + input_tensors_list=[datahandler.x_pde_list, train_dirichlet_input, train_dirichlet_output], + orig_factor_matrices=[ + datahandler.shape_val_mat_list, + datahandler.grad_x_mat_list, + datahandler.grad_y_mat_list, + ], + force_function_list=datahandler.forcing_function_list, + tensor_dtype=i_dtype, + use_attention=i_use_attention, + activation=i_activation, + hessian=False, + ) + + test_points = domain.get_test_points() + print(f"[bold]Number of Test Points = [/bold] {test_points.shape[0]}") + y_exact = exact_solution(test_points[:, 0], test_points[:, 1]) + + num_epochs = i_epochs # num_epochs + progress_bar = tqdm( + total=num_epochs, + desc='Training', + unit='epoch', + bar_format="{l_bar}{bar:40}{r_bar}{bar:-10b}", + colour="green", + ncols=100, + ) + loss_array = [] # total loss + test_loss_array = [] # test loss + time_array = [] # time per epoc + # beta - boundary loss parameters + beta = tf.constant(i_beta, dtype=i_dtype) + + # ---------------------------------------------------------------# + # ------------- TRAINING LOOP ---------------------------------- # + # ---------------------------------------------------------------# + for epoch in range(num_epochs): + + # Train the model + batch_start_time = time.time() + loss = model.train_step(beta=beta, bilinear_params_dict=bilinear_params_dict) + elapsed = time.time() - batch_start_time + + # print(elapsed) + time_array.append(elapsed) + + loss_array.append(loss['loss']) + + # ------ Intermediate results update ------ # + if (epoch + 1) % i_update_console_output == 0 or epoch == num_epochs - 1: + y_pred = model(test_points).numpy() + y_pred = y_pred.reshape(-1) + + error = np.abs(y_exact - y_pred) + + # get errors + ( + l2_error, + linf_error, + l2_error_relative, + linf_error_relative, + l1_error, + l1_error_relative, + ) = compute_errors_combined(y_exact, y_pred) + + loss_pde = float(loss['loss_pde'].numpy()) + loss_dirichlet = float(loss['loss_dirichlet'].numpy()) + total_loss = float(loss['loss'].numpy()) + + # Append test loss + test_loss_array.append(l1_error) + solution_array = np.c_[y_pred, y_exact, np.abs(y_exact - y_pred)] + domain.write_vtk( + solution_array, + output_path=i_output_path, + filename=f"prediction_{epoch+1}.vtk", + data_names=["Sol", "Exact", "Error"], + ) + + console.print(f"\nEpoch [bold]{epoch+1}/{num_epochs}[/bold]") + console.print("[bold]--------------------[/bold]") + console.print("[bold]Beta : [/bold]", beta.numpy(), end=" ") + console.print( + f"Variational Losses || Pde Loss : [red]{loss_pde:.3e}[/red] Dirichlet Loss : [red]{loss_dirichlet:.3e}[/red] Total Loss : [red]{total_loss:.3e}[/red]" + ) + console.print( + f"Test Losses || L1 Error : {l1_error:.3e} L2 Error : {l2_error:.3e} Linf Error : {linf_error:.3e}" + ) + + progress_bar.update(1) + + # Save the model + model.save_weights(str(Path(i_output_path) / "model_weights")) + + solution_array = np.c_[y_pred, y_exact, np.abs(y_exact - y_pred)] + domain.write_vtk( + solution_array, + output_path=i_output_path, + filename=f"prediction_{epoch+1}.vtk", + data_names=["Sol", "Exact", "Error"], + ) + + # print the Error values in table + print_table( + "Error Values", + ["Error Type", "Value"], + [ + "L2 Error", + "Linf Error", + "Relative L2 Error", + "Relative Linf Error", + "L1 Error", + "Relative L1 Error", + ], + [l2_error, linf_error, l2_error_relative, linf_error_relative, l1_error, l1_error_relative], + ) + + # print the time values in table + print_table( + "Time Values", + ["Time Type", "Value"], + [ + "Time per Epoch(s) - Median", + "Time per Epoch(s) IQR-25% ", + "Time per Epoch(s) IQR-75% ", + "Mean (s)", + "Epochs per second", + "Total Train Time", + ], + [ + np.median(time_array), + np.percentile(time_array, 25), + np.percentile(time_array, 75), + np.mean(time_array), + int(i_epochs / np.sum(time_array)), + np.sum(time_array), + ], + ) + + # save all the arrays as numpy arrays + np.savetxt(str(Path(i_output_path) / "loss_function.txt"), np.array(loss_array)) + np.savetxt(str(Path(i_output_path) / "prediction.txt"), y_pred) + np.savetxt(str(Path(i_output_path) / "exact.txt"), y_exact) + np.savetxt(str(Path(i_output_path) / "error.txt"), error) + np.savetxt(str(Path(i_output_path) / "time_per_epoch.txt"), np.array(time_array)) diff --git a/examples/forward_problems_2d/complex_mesh/helmholtz/utility.py b/examples/forward_problems_2d/complex_mesh/helmholtz/utility.py new file mode 100644 index 0000000..794a0ea --- /dev/null +++ b/examples/forward_problems_2d/complex_mesh/helmholtz/utility.py @@ -0,0 +1,113 @@ +import sys +import yaml +import numpy as np + +from fastvpinns.utils.plot_utils import plot_contour, plot_loss_function, plot_test_loss_function +from fastvpinns.utils.compute_utils import compute_errors_combined + + +def get_errors( + model, + console, + y_pred, + y_exact, + Y_Exact_Matrix, + i_n_test_points_x, + i_n_test_points_y, + i_output_path, + epoch, + loss, + num_epochs, +): + """ + Calculate and return various error metrics and loss values. + + Args: + model (object): The trained model. + console (object): The console object for printing messages. + y_exact (array): The exact solution. + Y_Exact_Matrix (array): The matrix of exact solutions. + i_n_test_points_x (int): The number of test points in the x-direction. + i_n_test_points_y (int): The number of test points in the y-direction. + i_output_path (str): The output path for saving plots. + epoch (int): The current epoch number. + loss (dict): The dictionary containing different loss values. + num_epochs (int): The total number of epochs. + + Returns: + dict: A dictionary containing various error metrics and loss values. + """ + + # Compute error metrics + l2_error, linf_error, l2_error_relative, linf_error_relative, l1_error, l1_error_relative = ( + compute_errors_combined(y_exact, y_pred) + ) + + # Print epoch information + console.print(f"\nEpoch [bold]{epoch+1}/{num_epochs}[/bold]") + console.print("[bold]--------------------[/bold]") + console.print( + f"Variational Losses || Pde Loss : [red]{loss_pde:.3e}[/red] Dirichlet Loss : [red]{loss_dirichlet:.3e}[/red] Total Loss : [red]{total_loss:.3e}[/red]" + ) + console.print(f"Test Losses || L1 Error : {l1_error:.3e}", end=" ") + console.print(f"L2 Error : {l2_error:.3e}", end=" ") + console.print(f"Linf Error : {linf_error:.3e}", end="\n") + + return { + 'l2_error': l2_error, + 'linf_error': linf_error, + 'l2_error_relative': l2_error_relative, + 'linf_error_relative': linf_error_relative, + 'l1_error': l1_error, + 'l1_error_relative': l1_error_relative, + 'loss_pde': loss_pde, + 'loss_dirichlet': loss_dirichlet, + 'total_loss': total_loss, + } + + +def plot_results( + loss_array, + test_loss_array, + y_pred, + X, + Y, + Y_Exact_Matrix, + i_output_path, + epoch, + i_n_test_points_x, + i_n_test_points_y, +): + """ + Plot the loss function, test loss function, solution, and error. + + Args: + loss_array (array): Array of loss values during training. + test_loss_array (array): Array of test loss values during training. + y_pred (array): Predicted solution. + X (array): X-coordinates of the grid. + Y (array): Y-coordinates of the grid. + Y_Exact_Matrix (array): Matrix of exact solutions. + i_output_path (str): Output path for saving plots. + epoch (int): Current epoch number. + i_n_test_points_x (int): Number of test points in the x-direction. + i_n_test_points_y (int): Number of test points in the y-direction. + """ + # plot loss + plot_loss_function(loss_array, i_output_path) # plots NN loss + plot_test_loss_function(test_loss_array, i_output_path) # plots test loss + + # plot solution + y_pred = y_pred.reshape(i_n_test_points_x, i_n_test_points_y) + error = np.abs(Y_Exact_Matrix - y_pred) + plot_contour( + x=X, + y=Y, + z=y_pred, + output_path=i_output_path, + filename=f"prediction_{epoch+1}", + title="Prediction", + ) + plot_contour( + x=X, y=Y, z=error, output_path=i_output_path, filename=f"error_{epoch+1}", title="Error" + ) diff --git a/examples/forward_problems_2d/complex_mesh/meshes/circle_quad.mesh b/examples/forward_problems_2d/complex_mesh/meshes/circle_quad.mesh new file mode 100644 index 0000000..09163ae --- /dev/null +++ b/examples/forward_problems_2d/complex_mesh/meshes/circle_quad.mesh @@ -0,0 +1,2252 @@ + MeshVersionFormatted 2 + Dimension + 3 + Vertices + 1090 + 0 0 0 1 + 1 0 0 2 + 0.99879545619965 0.049067674439865 0 1 + 0.99518472665017 0.0980171405532 0 1 + 0.98917650991663 0.14673047477995 0 1 + 0.9807852803193 0.19509032243808 0 1 + 0.97003125306368 0.2429801804257 0 1 + 0.95694033554573 0.29028467786921 0 1 + 0.94154406493047 0.33688985409805 0 1 + 0.92387953218303 0.38268343315756 0 1 + 0.90398929268859 0.42755509434971 0 1 + 0.88192126379111 0.47139673786853 0 1 + 0.8577286093219 0.51410274532502 0 1 + 0.83146961148846 0.55557023423797 0 1 + 0.80320753052993 0.59569930577432 0 1 + 0.77301045226514 0.63439328550107 0 1 + 0.74095112411604 0.67155895621396 0 1 + 0.7071067797985 0.7071067825746 0 1 + 0.67155895327831 0.74095112677676 0 1 + 0.6343932824239 0.77301045479051 0 1 + 0.59569930256087 0.80320753291319 0 1 + 0.55557023090199 0.83146961371749 0 1 + 0.51410274189913 0.8577286113753 0 1 + 0.47139673433984 0.88192126567723 0 1 + 0.42755509074558 0.90398929439321 0 1 + 0.38268342947462 0.92387953370856 0 1 + 0.33688985027438 0.9415440662986 0 1 + 0.29028467392046 0.95694033674357 0 1 + 0.24298017636823 0.97003125408002 0 1 + 0.19509031828524 0.98078528114535 0 1 + 0.14673047051843 0.98917651054877 0 1 + 0.098017136182996 0.9951847270806 0 1 + 0.049067670007772 0.99879545641738 0 1 + -4.4840768263463E-09 1 0 1 + -0.049067678955195 0.99879545597782 0 1 + -0.098017145096387 0.99518472620271 0 1 + -0.14673047934988 0.98917650923875 0 1 + -0.19509032702091 0.98078527940772 0 1 + -0.2429801849891 0.97003125192061 0 1 + -0.29028468239788 0.95694033417197 0 1 + -0.33688985859523 0.94154406332136 0 1 + -0.38268343762212 0.92387953033376 0 1 + -0.42755509875601 0.90398929060456 0 1 + -0.47139674219487 0.88192126147863 0 1 + -0.51410274955405 0.85772860678711 0 1 + -0.55557023836754 0.83146960872917 0 1 + -0.59569930975506 0.80320752757762 0 1 + -0.63439328933735 0.77301044911679 0 1 + -0.6715589598968 0.7409511207781 0 1 + -0.70710678610147 0.70710677627163 0 1 + -0.74095113011578 0.67155894959426 0 1 + -0.77301045795692 0.63439327856561 0 1 + -0.80320753586268 0.59569929858394 0 1 + -0.8314696164943 0.55557022674619 0 1 + -0.8577286139607 0.51410273758564 0 1 + -0.88192126805308 0.47139672989494 0 1 + -0.90398929655134 0.42755508618261 0 1 + -0.92387953563008 0.38268342483567 0 1 + -0.94154406798222 0.33688984556899 0 1 + -0.9569403381831 0.29028466917495 0 1 + -0.97003125528343 0.24298017156397 0 1 + -0.98078528211022 0.19509031343451 0 1 + -0.98917651127093 0.14673046565001 0 1 + -0.99518472755972 0.098017131318396 0 1 + -0.99879545665646 0.049067665141258 0 1 + -1 -9.3591293489555E-09 0 1 + -0.99879545575347 -0.04906768352208 0 1 + -0.99518472578625 -0.098017149324774 0 1 + -0.98917650866081 -0.14673048324599 0 1 + -0.98078527872428 -0.19509033045679 0 1 + -0.97003125112631 -0.24298018816012 0 1 + -0.95694033327956 -0.29028468533976 0 1 + -0.94154406241289 -0.33688986113422 0 1 + -0.92387952942832 -0.38268343980803 0 1 + -0.90398928972469 -0.42755510061635 0 1 + -0.88192126066675 -0.47139674371381 0 1 + -0.85772860605824 -0.51410275077011 0 1 + -0.8314696081206 -0.55557023927833 0 1 + -0.80320752708849 -0.59569931041457 0 1 + -0.77301044877763 -0.63439328975062 0 1 + -0.74095112059968 -0.67155896009366 0 1 + -0.70710677625465 -0.70710678611845 0 1 + -0.67155894973502 -0.7409511299882 0 1 + -0.63439327892635 -0.77301045766088 0 1 + -0.5956992991796 -0.80320753542091 0 1 + -0.55557022760009 -0.83146961592375 0 1 + -0.51410273878081 -0.85772861324434 0 1 + -0.47139673142234 -0.88192126723667 0 1 + -0.42755508814847 -0.90398929562155 0 1 + -0.38268342718319 -0.9238795346577 0 1 + -0.33688984825967 -0.94154406701948 0 1 + -0.29028467213291 -0.95694033728582 0 1 + -0.24298017483291 -0.9700312544646 0 1 + -0.19509031706934 -0.98078528138721 0 1 + -0.14673046954049 -0.98917651069383 0 1 + -0.098017135458384 -0.99518472715197 0 1 + -0.0490676695566 -0.99879545643955 0 1 + 4.7742101766839E-09 -1 0 1 + 0.04906767891433 -0.99879545597983 0 1 + 0.098017144776 -0.99518472623426 0 1 + 0.14673047864562 -0.98917650934321 0 1 + 0.19509032590819 -0.98078527962905 0 1 + 0.24298018346934 -0.97003125230129 0 1 + 0.29028468058221 -0.95694033472275 0 1 + 0.33688985651818 -0.94154406406453 0 1 + 0.38268343529093 -0.92387953129937 0 1 + 0.42755509623402 -0.90398929179737 0 1 + 0.47139673949853 -0.88192126291986 0 1 + 0.51410274665093 -0.85772860852718 0 1 + 0.55557023533891 -0.83146961075284 0 1 + 0.59569930667891 -0.80320752985904 0 1 + 0.63439328619843 -0.77301045169284 0 1 + 0.67155895673606 -0.74095112364283 0 1 + 0.70710678288319 -0.70710677948991 0 1 + 0.74095112682057 -0.67155895322997 0 1 + 0.77301045462195 -0.63439328262929 0 1 + 0.80320753256387 -0.59569930303188 0 1 + 0.83146961323567 -0.55557023162308 0 1 + 0.85772861078264 -0.51410274288792 0 1 + 0.88192126498727 -0.47139673563068 0 1 + 0.90398929362633 -0.42755509236703 0 1 + 0.923879532878 -0.38268343147978 0 1 + 0.94154406543215 -0.33688985269595 0 1 + 0.95694033590135 -0.29028467669689 0 1 + 0.97003125333035 -0.24298017936111 0 1 + 0.98078528048503 -0.19509032160491 0 1 + 0.98917651001211 -0.14673047413627 0 1 + 0.99518472669183 -0.098017140130269 0 1 + 0.99879545620924 -0.04906767424457 0 1 + 7.5793211331687E-11 -1.8743022542173E-09 0 1 + -0.35040490753947 0.35040490217645 0 1 + 0.35040490477337 0.3504049050229 0 1 + -2.8907976971714E-09 0.66146400876605 0 1 + -0.35040490325429 -0.35040490869081 0 1 + -0.66146400979884 -5.563461518704E-09 0 1 + 0.35040490628272 -0.35040490571589 0 1 + 2.8847312582668E-09 -0.66146401081181 0 1 + 0.66146400985334 3.5122083978278E-10 0 1 + -0.18851805072209 0.79325192019767 0 1 + 0.18851804373881 0.79325192186998 0 1 + -3.9504795915318E-09 0.89266377425581 0 1 + -0.52626371726518 0.52626417366679 0 1 + -0.1785942663467 0.51091727259825 0 1 + -0.36423261084496 0.66950821552214 0 1 + -0.17516604380426 0.17516604015664 0 1 + 0.17516604236155 0.17516604172439 0 1 + 0.17859426189731 0.51091727419523 0 1 + -1.4809352860777E-09 0.3449162104121 0 1 + 0.52626417670814 0.52626371426429 0 1 + 0.36423262318338 0.66950822691203 0 1 + -0.79325192031525 -0.18851805318123 0 1 + -0.79325192328693 0.18851804012327 0 1 + -0.89266377467496 -7.5551239318939E-09 0 1 + -0.52626417423093 -0.52626371788319 0 1 + -0.51091727352982 -0.17859426816892 0 1 + -0.66950821571828 -0.3642326122602 0 1 + -0.17516604168743 -0.17516604544127 0 1 + -0.5109172760584 0.17859425916309 0 1 + -0.34491621201071 -3.5909660937648E-09 0 1 + -0.66950822920077 0.36423261975911 0 1 + 0.18851804961196 -0.79325192168456 0 1 + -0.18851804264187 -0.79325192337724 0 1 + 3.9492611219723E-09 -0.89266377505235 0 1 + 0.52626371505255 -0.52626417708685 0 1 + 0.17859426553577 -0.51091727535522 0 1 + 0.36423260898858 -0.66950821790698 0 1 + 0.1751660434148 -0.17516604382251 0 1 + -0.17859426094839 -0.51091727702602 0 1 + 1.5866775649018E-09 -0.34491621365039 0 1 + -0.3642326211535 -0.66950822942568 0 1 + 0.79325192160756 0.18851804724076 0 1 + 0.79325192205012 -0.18851804604161 0 1 + 0.89266377467666 5.0481448352303E-10 0 1 + 0.51091727452645 0.17859426371609 0 1 + 0.66950821782792 0.3642326074951 0 1 + 0.51091727526451 -0.17859426354309 0 1 + 0.34491621213876 -4.8084585331528E-10 0 1 + 0.66950822725181 -0.36423262440403 0 1 + -0.096930398056666 0.93621496708507 0 1 + 0.096930389741373 0.93621496794606 0 1 + -4.3105841440793E-09 0.96652194798953 0 1 + -0.28479014066797 0.85709959955447 0 1 + -0.09541340641146 0.84545940921759 0 1 + -0.19213359645943 0.9000354133127 0 1 + -0.093319979505666 0.72882542809939 0 1 + 0.093319973113464 0.72882542892819 0 1 + 0.095413398954444 0.84545941006226 0 1 + -3.4684082210561E-09 0.78906596269675 0 1 + 0.28479013310055 0.85709960207755 0 1 + 0.19213358849815 0.90003541501433 0 1 + -0.45882081504718 0.74896793101655 0 1 + -0.27792287827554 0.73399184898303 0 1 + -0.37370132072001 0.80637672266788 0 1 + -0.61534453772795 0.61534455780897 0 1 + -0.44714911836686 0.60010457460001 0 1 + -0.53952336913867 0.6850788816111 0 1 + -0.43811846178984 0.43811848396065 0 1 + -0.26553902143197 0.43176587380178 0 1 + -0.27070661404557 0.59067367102445 0 1 + -0.35584834182339 0.51600959774137 0 1 + -0.09027082198705 0.58788442924974 0 1 + -0.18324814069151 0.66188111528993 0 1 + -0.088687865078166 0.42858896709959 0 1 + 0.088687861365975 0.42858896789063 0 1 + 0.090270816855678 0.58788443005478 0 1 + -2.2145563578556E-09 0.5094249293292 0 1 + -0.26272901480467 0.26272901017036 0 1 + -0.088067085252515 0.26052401841811 0 1 + -0.17644818694981 0.34642016356602 0 1 + -0.087570765383195 0.087570762701771 0 1 + 0.087570764739364 0.087570763489976 0 1 + 0.088067083045737 0.2605240192044 0 1 + -7.1355992894788E-10 0.17428040024948 0 1 + 0.26272901256289 0.26272901251474 0 1 + 0.26553901817404 0.43176587639124 0 1 + 0.17644818396667 0.3464201651406 0 1 + 0.27792287190572 0.73399185150751 0 1 + 0.45882080938017 0.74896793556855 0 1 + 0.3737013135763 0.80637672599967 0 1 + 0.27070660985623 0.59067367388926 0 1 + 0.18324813488798 0.66188111692566 0 1 + 0.43811848677338 0.4381184590371 0 1 + 0.44714994866722 0.60010494003598 0 1 + 0.35584838926206 0.51600962350758 0 1 + 0.61534456108397 0.61534453447382 0 1 + 0.5395234150117 0.68507890902301 0 1 + -0.9362149669707 -0.096930401612844 0 1 + -0.93621496862023 0.096930385527911 0 1 + -0.96652194814039 -8.5265996518527E-09 0 1 + -0.85709959918422 -0.28479014299949 0 1 + -0.84545940944408 -0.095413409439107 0 1 + -0.90003541301377 -0.19213359941787 0 1 + -0.72882542868462 -0.093319982084073 0 1 + -0.72882543012729 0.09331996997838 0 1 + -0.84545941099227 0.095413395326867 0 1 + -0.78906596342179 -6.5629176856269E-09 0 1 + -0.85709960373813 0.28479012898875 0 1 + -0.90003541619039 0.19213358431859 0 1 + -0.74896793082435 -0.45882081623092 0 1 + -0.73399184910261 -0.27792288019381 0 1 + -0.80637672234269 -0.37370132245257 0 1 + -0.61534455809609 -0.61534453806198 0 1 + -0.60010457493765 -0.44714911934097 0 1 + -0.68507888162269 -0.53952336985266 0 1 + -0.43811848478965 -0.43811846268102 0 1 + -0.43176587475718 -0.26553902287573 0 1 + -0.59067367159554 -0.27070661567574 0 1 + -0.51600959839448 -0.35584834304141 0 1 + -0.58788443020505 -0.090270824223215 0 1 + -0.66188111583603 -0.1832481427813 0 1 + -0.42858896837294 -0.088687867056627 0 1 + -0.4285889696055 0.088687858951523 0 1 + -0.58788443151269 0.090270814136379 0 1 + -0.50942493067321 -4.554164155253E-09 0 1 + -0.26272901148412 -0.2627290162068 0 1 + -0.26052401993578 -0.088067087085079 0 1 + -0.34642016481073 -0.17644818859788 0 1 + -0.087570764420192 -0.087570767227454 0 1 + -0.2605240210951 0.088067080838865 0 1 + -0.17428040200808 -2.69879317001E-09 0 1 + -0.43176587862757 0.26553901546222 0 1 + -0.34642016719271 0.17644818151449 0 1 + -0.73399185337494 0.27792286836335 0 1 + -0.74896793809578 0.45882080559645 0 1 + -0.80637672811121 0.37370130959879 0 1 + -0.59067367595104 0.27070660678344 0 1 + -0.66188111856828 0.18324813176549 0 1 + -0.60010494271289 0.4471499454015 0 1 + -0.51600962595494 0.35584838627878 0 1 + -0.68507891193674 0.53952341145835 0 1 + 0.096930397505966 -0.93621496760402 0 1 + -0.09693038912137 -0.93621496847064 0 1 + 4.4233363827314E-09 -0.96652194826522 0 1 + 0.2847901389747 -0.85709960079106 0 1 + 0.095413405820698 -0.84545941033428 0 1 + 0.19213359528508 -0.90003541415649 0 1 + 0.093319978960748 -0.72882542984687 0 1 + -0.09331997259474 -0.72882543069083 0 1 + -0.095413398399747 -0.84545941118161 0 1 + 3.4441549483637E-09 -0.78906596411174 0 1 + -0.28479013140227 -0.85709960333323 0 1 + -0.19213358733519 -0.90003541585969 0 1 + 0.45882081263711 -0.74896793322257 0 1 + 0.27792287675227 -0.73399185089942 0 1 + 0.37370131862463 -0.80637672436251 0 1 + 0.61534453501677 -0.61534456115639 0 1 + 0.44714911627295 -0.60010457748216 0 1 + 0.53952336653459 -0.68507888435639 0 1 + 0.43811846006617 -0.43811848744113 0 1 + 0.2655390203186 -0.43176587694409 0 1 + 0.27070661272396 -0.59067367358728 0 1 + 0.35584834022989 -0.51600960075078 0 1 + 0.090270821548129 -0.58788443163659 0 1 + 0.18324813972329 -0.6618811174285 0 1 + 0.088687864741362 -0.4285889700882 0 1 + -0.088687860862777 -0.42858897091752 0 1 + -0.090270816363722 -0.58788443247449 0 1 + 2.2644385034294E-09 -0.50942493202184 0 1 + 0.26272901399691 -0.26272901377283 0 1 + 0.088067085023166 -0.26052402187153 0 1 + 0.17644818629309 -0.34642016685977 0 1 + 0.087570765360778 -0.087570766422819 0 1 + -0.088067082559996 -0.26052402269201 0 1 + 8.541572263091E-10 -0.17428040385747 0 1 + -0.26553901684392 -0.43176587964417 0 1 + -0.17644818307872 -0.34642016850704 0 1 + -0.27792287030523 -0.73399185349409 0 1 + -0.4588208067527 -0.74896793793148 0 1 + -0.37370131135665 -0.80637672778175 0 1 + -0.27070660839013 -0.59067367655436 0 1 + -0.18324813386858 -0.66188111911826 0 1 + -0.44714994632985 -0.60010494309775 0 1 + -0.35584838744631 -0.51600962666154 0 1 + -0.53952341212636 -0.68507891199145 0 1 + 0.93621496773538 0.096930394050613 0 1 + 0.93621496784683 -0.096930393131304 0 1 + 0.96652194813667 3.3555837638156E-10 0 1 + 0.85709960117807 0.28479013670696 0 1 + 0.84545941014142 0.095413402933539 0 1 + 0.90003541445406 0.1921335924598 0 1 + 0.72882542932063 0.09331997649893 0 1 + 0.72882542957016 -0.09331997554692 0 1 + 0.84545941031896 -0.095413401833907 0 1 + 0.78906596344532 5.1392274031652E-10 0 1 + 0.85709960177769 -0.28479013526218 0 1 + 0.90003541475525 -0.19213359130007 0 1 + 0.74896793353914 0.45882081132351 0 1 + 0.73399185085291 0.27792287483911 0 1 + 0.80637672475311 0.37370131685129 0 1 + 0.60010457730575 0.44714911515564 0 1 + 0.68507888453271 0.53952336562214 0 1 + 0.43176587611036 0.26553901881105 0 1 + 0.59067367312602 0.2707066110604 0 1 + 0.51600960023859 0.3558483389121 0 1 + 0.58788443076611 0.090270819386494 0 1 + 0.66188111696172 0.18324813767795 0 1 + 0.42858896891014 0.08868786278865 0 1 + 0.42858896929686 -0.088687863181442 0 1 + 0.58788443110456 -0.090270818940443 0 1 + 0.50942493076772 1.3551306899396E-11 0 1 + 0.26052402043308 0.08806708318003 0 1 + 0.346420165716 0.17644818461 0 1 + 0.26052402087681 -0.088067084709756 0 1 + 0.17428040215445 -1.118303990044E-09 0 1 + 0.43176587752176 -0.26553901941727 0 1 + 0.34642016654968 -0.1764481854299 0 1 + 0.73399185172799 -0.27792287364967 0 1 + 0.7489679355183 -0.45882081036404 0 1 + 0.80637672578246 -0.37370131511604 0 1 + 0.59067367460179 -0.27070661129979 0 1 + 0.66188111756861 -0.18324813681522 0 1 + 0.60010494056647 -0.44714994941904 0 1 + 0.51600962434537 -0.35584839026728 0 1 + 0.68507890922789 -0.53952341550061 0 1 + -0.048917591737021 0.98066956665595 0 1 + 0.048917582973927 0.98066956709324 0 1 + -4.4285691939269E-09 0.98991976896247 0 1 + -0.14587825868816 0.95808346076474 0 1 + -0.048613075284447 0.95180829647179 0 1 + -0.097557413389404 0.97013250727064 0 1 + -0.048324248205833 0.91455210519905 0 1 + 0.048324240096596 0.91455210562786 0 1 + 0.04861306681239 0.95180829690428 0 1 + -4.1464611862045E-09 0.93342779968008 0 1 + 0.14587825016602 0.95808346206234 0 1 + 0.097557404740282 0.97013250814029 0 1 + -0.2410302780867 0.92800728092542 0 1 + -0.14475079638362 0.91879446318494 0 1 + -0.19370456284103 0.94393771268143 0 1 + -0.33350927967381 0.88998498511721 0 1 + -0.23879462677314 0.8793320635448 0 1 + -0.28763196243132 0.90992256350789 0 1 + -0.23650127558136 0.82500176859344 0 1 + -0.14227486126659 0.81994019512814 0 1 + -0.14362970328013 0.87268882470926 0 1 + -0.19038733585486 0.84951660257845 0 1 + -0.047891086984462 0.86946026322161 0 1 + -0.096177159271604 0.89414935802612 0 1 + -0.047538668398623 0.8174970944773 0 1 + 0.047538661199954 0.81749709489822 0 1 + 0.047891079302662 0.86946026364564 0 1 + -3.7212936398729E-09 0.84380659965608 0 1 + -0.14075886088028 0.7611314879636 0 1 + -0.046953843468332 0.75945304170666 0 1 + -0.094453627291234 0.78987417790779 0 1 + -0.04637666351533 0.69555465070357 0 1 + 0.046376657425802 0.69555465111579 0 1 + 0.046953836800843 0.75945304212315 0 1 + -3.1907610154023E-09 0.72798864527619 0 1 + 0.14075885419174 0.76113148921295 0 1 + 0.14227485404348 0.81994019638856 0 1 + 0.094453620344545 0.78987417874497 0 1 + 0.14475078824015 0.91879446446852 0 1 + 0.24103026987024 0.92800728306039 0 1 + 0.19370455446351 0.9439377144008 0 1 + 0.14362969557093 0.87268882598109 0 1 + 0.096177151358585 0.89414935887835 0 1 + 0.23650126830619 0.82500177069042 0 1 + 0.23879461900569 0.87933206565888 0 1 + 0.19038732835961 0.84951660426471 0 1 + 0.33350927181349 0.88998498806739 0 1 + 0.28763195438927 0.90992256605233 0 1 + -0.42227758784681 0.84365732608643 0 1 + -0.32964090130425 0.83249865438802 0 1 + -0.37833925122794 0.86772435950284 0 1 + -0.50687983040671 0.78975243717013 0 1 + -0.41668569870772 0.77835424511783 0 1 + -0.4650892319567 0.81754264451377 0 1 + -0.41134983381555 0.70901833456509 0 1 + -0.32138805433629 0.70222473133428 0 1 + -0.32565000221561 0.76997425098873 0 1 + -0.36886619214792 0.74007152427998 0 1 + -0.23356230965764 0.76422437482504 0 1 + -0.28144461350867 0.7981662407184 0 1 + -0.58659907946307 0.72860977632765 0 1 + -0.4996549052226 0.71766659728754 0 1 + -0.5473257666846 0.75996777359697 0 1 + -0.66082283541792 0.66082283049232 0 1 + -0.57801247435058 0.6508396677772 0 1 + -0.62438931289046 0.69545939831744 0 1 + -0.57058916817052 0.5705893336559 0 1 + -0.48715788754373 0.56366309444197 0 1 + -0.4931415352589 0.64237492973723 0 1 + -0.53237922411463 0.60703388568715 0 1 + -0.40603316554162 0.6352510417204 0 1 + -0.45265596190478 0.67623779746953 0 1 + -0.40138409434863 0.5579950861955 0 1 + -0.3135209557443 0.55364163023902 0 1 + -0.3173414129574 0.63006790502804 0 1 + -0.35965889524143 0.59441070175495 0 1 + -0.48208789304946 0.48208805957943 0 1 + -0.39735094887665 0.47743930308498 0 1 + -0.44215190654514 0.52047599078216 0 1 + -0.39420311996572 0.39420311820686 0 1 + -0.30826214940813 0.39136456330508 0 1 + -0.31056212747766 0.4739353668268 0 1 + -0.35271669860056 0.4344031224451 0 1 + -0.22223112724238 0.47151364603891 0 1 + -0.22444940011488 0.55095661529992 0 1 + -0.26770872573595 0.51268756931714 0 1 + -0.23044388278296 0.6979688570852 0 1 + -0.13859123737246 0.69588573089815 0 1 + -0.18592975899576 0.7301303001444 0 1 + -0.22720732614862 0.62661277428446 0 1 + -0.27416537383602 0.66443221811821 0 1 + -0.1346010772929 0.5496029562212 0 1 + -0.13651533333716 0.6251852350095 0 1 + -0.18067935944224 0.58835056840197 0 1 + -0.045416956953829 0.62511376220051 0 1 + -0.091740691612322 0.66088060922467 0 1 + -0.04490149424362 0.54898603046436 0 1 + 0.044901489461447 0.54898603086483 0 1 + 0.045416951494428 0.62511376260528 0 1 + -2.5616872846839E-09 0.58745848695615 0 1 + -0.13345649907686 0.46994280791984 0 1 + -0.04446177451509 0.46914680478105 0 1 + -0.089319034576612 0.50964473097144 0 1 + -0.044261387816456 0.38682859692225 0 1 + 0.044261384479064 0.38682859731703 0 1 + 0.044461770443445 0.46914680517762 0 1 + -1.8526023912284E-09 0.42810075827721 0 1 + 0.1334564949925 0.46994280911079 0 1 + 0.13460107249808 0.54960295742259 0 1 + 0.089319030141615 0.50964473176829 0 1 + -0.22088100077084 0.38916544775042 0 1 + -0.13267621868626 0.38761698497847 0 1 + -0.17730292358943 0.42970031893406 0 1 + -0.30653088036145 0.30653087525581 0 1 + -0.2198010429688 0.30478065085397 0 1 + -0.26396095634495 0.34809589837771 0 1 + -0.21892110499615 0.21892110085849 0 1 + -0.13175669867649 0.21798122799473 0 1 + -0.13220409236874 0.30349812943268 0 1 + -0.17574153554979 0.26138464490062 0 1 + -0.044101612561779 0.30278504624218 0 1 + -0.08832100860548 0.34525484093191 0 1 + -0.043995039743207 0.21743046437101 0 1 + 0.043995037926073 0.21743046476419 0 1 + 0.044101609976904 0.30278504663572 0 1 + -1.1006947410166E-09 0.26015634746647 0 1 + -0.13135698710089 0.13135698394272 0 1 + -0.043857799868066 0.13099114216508 0 1 + -0.087783953914294 0.17449735364725 0 1 + -0.043778701410867 0.043778699184741 0 1 + 0.04377870116528 0.043778699580241 0 1 + 0.043857798832057 0.13099114255882 0 1 + -3.2041985006202E-10 0.087415574058624 0 1 + 0.1313569860579 0.13135698512115 0 1 + 0.13175669685045 0.21798122917241 0 1 + 0.087783952483274 0.17449735443321 0 1 + 0.13267621533722 0.38761698616206 0 1 + 0.22088099745032 0.38916544974356 0 1 + 0.22223112326168 0.47151364807946 0 1 + 0.17730291987409 0.42970032052241 0 1 + 0.13220408977315 0.3034981306124 0 1 + 0.088321005638156 0.3452548417198 0 1 + 0.21892110315392 0.21892110281471 0 1 + 0.21980104036225 0.30478065281889 0 1 + 0.17574153332986 0.26138464647007 0 1 + 0.30653087774737 0.30653087796129 0 1 + 0.30826214805643 0.39136456687472 0 1 + 0.26396095355059 0.34809590081726 0 1 + 0.32964089394254 0.8324986573168 0 1 + 0.4222775803528 0.84365732984802 0 1 + 0.37833924354502 0.86772436286049 0 1 + 0.23356230293391 0.76422437690623 0 1 + 0.32564999545884 0.76997425391468 0 1 + 0.28144460646743 0.79816624322263 0 1 + 0.32138805024032 0.70222473514559 0 1 + 0.4113498354804 0.70901834178224 0 1 + 0.41668569192255 0.77835424889776 0 1 + 0.36886618663157 0.74007152803862 0 1 + 0.50687982352359 0.78975244178636 0 1 + 0.46508922469976 0.81754264867863 0 1 + 0.13859123126939 0.69588573213191 0 1 + 0.23044387669441 0.69796885916317 0 1 + 0.18592975258228 0.73013030180086 0 1 + 0.13651532786672 0.62518523622715 0 1 + 0.091740685828646 0.66088061004172 0 1 + 0.22444939546406 0.55095661738095 0 1 + 0.22720732077646 0.62661277637085 0 1 + 0.18067935431726 0.58835057002568 0 1 + 0.31734141535889 0.63006791140237 0 1 + 0.27416536902425 0.66443222103035 0 1 + 0.3135209626617 0.55364163823758 0 1 + 0.40138440167836 0.55799522393523 0 1 + 0.40603332474174 0.63525111783835 0 1 + 0.35965896093907 0.59441073606101 0 1 + 0.31056213123278 0.47393537301646 0 1 + 0.26770872328778 0.51268757260484 0 1 + 0.3942031209089 0.39420311733372 0 1 + 0.39735110512565 0.47743936939039 0 1 + 0.35271671938458 0.43440313501901 0 1 + 0.48208806250435 0.48208789017474 0 1 + 0.48715998836703 0.56366391424867 0 1 + 0.44215268779914 0.52047629142686 0 1 + 0.49965491061432 0.71766660695563 0 1 + 0.58659908081103 0.72860978496814 0 1 + 0.54732576192189 0.75996777938715 0 1 + 0.49314184180765 0.64237506829943 0 1 + 0.45265602684154 0.67623783260964 0 1 + 0.57058933681241 0.57058916504478 0 1 + 0.57801262899368 0.65083973569696 0 1 + 0.53238000457036 0.60703418713997 0 1 + 0.66082283388892 0.66082283203189 0 1 + 0.62438933105675 0.69545941323755 0 1 + -0.98066956653006 -0.048917595956728 0 1 + -0.98066956740426 0.048917578431595 0 1 + -0.98991976901113 -8.9780185593575E-09 0 1 + -0.95808346036893 -0.14587826220547 0 1 + -0.95180829648135 -0.048613079170908 0 1 + -0.97013250699585 -0.097557417269927 0 1 + -0.91455210535501 -0.048324251789394 0 1 + -0.91455210616956 0.048324236190561 0 1 + -0.95180829732011 0.048613062595875 0 1 + -0.93342779995957 -8.0438080460164E-09 0 1 + -0.95808346287959 0.14587824563862 0 1 + -0.97013250870655 0.097557400200892 0 1 + -0.92800728034248 -0.24103028101873 0 1 + -0.91879446296868 -0.14475079963785 0 1 + -0.94393771218188 -0.19370456605865 0 1 + -0.8899849844859 -0.33350928193653 0 1 + -0.87933206319814 -0.23879462941785 0 1 + -0.90992256288761 -0.28763196502605 0 1 + -0.82500176847125 -0.23650127797782 0 1 + -0.81994019529024 -0.14227486400847 0 1 + -0.87268882467772 -0.14362970627225 0 1 + -0.84951660249055 -0.19038733854843 0 1 + -0.86946026353735 -0.047891090298614 0 1 + -0.89414935807987 -0.096177162557326 0 1 + -0.81749709495589 -0.047538671461035 0 1 + -0.81749709572067 0.047538657840786 0 1 + -0.86946026432266 0.047891075683701 0 1 + -0.84380660022776 -7.0600357748932E-09 0 1 + -0.76113148831772 -0.14075886340066 0 1 + -0.75945304235319 -0.046953846302453 0 1 + -0.78987417831476 -0.0944536300806 0 1 + -0.69555465151562 -0.046376666144878 0 1 + -0.69555465222428 0.046376654524613 0 1 + -0.75945304308843 0.046953833681783 0 1 + -0.72798864615671 -6.06255491186E-09 0 1 + -0.76113149051728 0.14075885081841 0 1 + -0.81994019756533 0.14227485041695 0 1 + -0.78987417981162 0.094453616973616 0 1 + -0.9187944653955 0.14475078404021 0 1 + -0.92800728436795 0.24103026540744 0 1 + -0.94393771546447 0.19370454996419 0 1 + -0.87268882703108 0.14362969166951 0 1 + -0.89414935967637 0.096177147451733 0 1 + -0.8250017722269 0.23650126444529 0 1 + -0.87933206707985 0.2387946148545 0 1 + -0.84951660556098 0.19038732447324 0 1 + -0.88998498985691 0.33350926744209 0 1 + -0.90992256760309 0.28763194996537 0 1 + -0.84365732552333 -0.42227758947794 0 1 + -0.83249865402917 -0.32964090333274 0 1 + -0.86772435889184 -0.37833925317281 0 1 + -0.78975243677264 -0.50687983146203 0 1 + -0.77835424485082 -0.41668570015951 0 1 + -0.81754264402266 -0.46508923329367 0 1 + -0.70901833456968 -0.41134983511792 0 1 + -0.70222473148579 -0.32138805599825 0 1 + -0.7699742508894 -0.32565000404302 0 1 + -0.74007152422539 -0.36886619370712 0 1 + -0.76422437493428 -0.23356231184314 0 1 + -0.79816624059753 -0.28144461561704 0 1 + -0.72860977616707 -0.58659908003301 0 1 + -0.71766659718985 -0.49965490616314 0 1 + -0.75996777330897 -0.5473257674889 0 1 + -0.66082283063011 -0.66082283559949 0 1 + -0.6508396679182 -0.57801247486377 0 1 + -0.69545939830068 -0.62438931325303 0 1 + -0.57058933408463 -0.57058916864938 0 1 + -0.56366309488163 -0.48715788832915 0 1 + -0.64237492991409 -0.49314153610611 0 1 + -0.60703388597976 -0.53237922476715 0 1 + -0.63525104198058 -0.40603316672938 0 1 + -0.67623779755325 -0.45265596297185 0 1 + -0.55799508669269 -0.40138409544689 0 1 + -0.55364163084449 -0.3135209571623 0 1 + -0.63006790541334 -0.31734141448224 0 1 + -0.59441070218935 -0.35965889654637 0 1 + -0.48208806027874 -0.48208789380643 0 1 + -0.47743930381285 -0.39735094991946 0 1 + -0.52047599136793 -0.44215190746135 0 1 + -0.3942031191634 -0.39420312098955 0 1 + -0.39136456430716 -0.30826215069294 0 1 + -0.47393536763315 -0.31056212881125 0 1 + -0.43440312331231 -0.35271669976672 0 1 + -0.47151364697611 -0.22223112886992 0 1 + -0.55095661605335 -0.22444940184441 0 1 + -0.51268757009042 -0.26770872726167 0 1 + -0.69796885742011 -0.23044388478891 0 1 + -0.6958857314554 -0.13859123970367 0 1 + -0.73013030047989 -0.18592976125587 0 1 + -0.6266127748377 -0.22720732800497 0 1 + -0.66443221847235 -0.27416537559717 0 1 + -0.54960295716028 -0.13460107931928 0 1 + -0.62518523576258 -0.13651533550384 0 1 + -0.58835056915029 -0.18067936138716 0 1 + -0.62511376318716 -0.045416959405472 0 1 + -0.66088060999917 -0.09174069400763 0 1 + -0.54898603161623 -0.044901496535222 0 1 + -0.54898603225988 0.04490148693426 0 1 + -0.62511376385343 0.045416948794239 0 1 + -0.58745848814937 -5.0550951029562E-09 0 1 + -0.46994280902431 -0.13345650098044 0 1 + -0.46914680608613 -0.044461776671935 0 1 + -0.50964473209558 -0.089319036671744 0 1 + -0.38682859836045 -0.044261389863258 0 1 + -0.38682859897084 0.044261382218748 0 1 + -0.4691468067094 0.044461768063655 0 1 + -0.4281007597589 -4.0638707251705E-09 0 1 + -0.46994281089541 0.1334564924201 0 1 + -0.54960295908581 0.13460106976832 0 1 + -0.50964473336058 0.089319027588914 0 1 + -0.38916544885266 -0.22088100231945 0 1 + -0.38761698623151 -0.13267622049448 0 1 + -0.42970032003114 -0.17730292531021 0 1 + -0.30653087645494 -0.30653088164094 0 1 + -0.30478065211861 -0.21980104448115 0 1 + -0.34809589951346 -0.26396095774597 0 1 + -0.21892110228443 -0.21892110651896 0 1 + -0.21798122950465 -0.13175670039872 0 1 + -0.30349813081656 -0.13220409411177 0 1 + -0.26138464629081 -0.17574153716984 0 1 + -0.30278504779468 -0.044101614528265 0 1 + -0.34525484233703 -0.088321010495409 0 1 + -0.21743046601577 -0.043995041658363 0 1 + -0.21743046658284 0.04399503583527 0 1 + -0.30278504838632 0.044101607812692 0 1 + -0.26015634915836 -3.1353830770243E-09 0 1 + -0.13135698557479 -0.13135698884844 0 1 + -0.13099114388923 -0.043857801770141 0 1 + -0.17449735527121 -0.08778395573293 0 1 + -0.043778700960613 -0.043778703324402 0 1 + -0.13099114440126 0.043857796805101 0 1 + -0.087415575853081 -2.2777511564448E-09 0 1 + -0.21798123117347 0.1317566946295 0 1 + -0.17449735634876 0.087783950364786 0 1 + -0.38761698805137 0.13267621289813 0 1 + -0.38916545188451 0.22088099487037 0 1 + -0.47151365013482 0.22223112053307 0 1 + -0.429700322491 0.1773029172921 0 1 + -0.3034981325809 0.13220408744593 0 1 + -0.34525484353694 0.0883210033385 0 1 + -0.30478065500503 0.2198010379252 0 1 + -0.26138464856078 0.17574153100337 0 1 + -0.3913645692653 0.30826214538819 0 1 + -0.34809590310278 0.2639609510002 0 1 + -0.83249865920686 0.32964088989032 0 1 + -0.84365733208913 0.42227757614601 0 1 + -0.86772436488113 0.37833923924472 0 1 + -0.76422437855186 0.23356229934947 0 1 + -0.7699742559022 0.3256499917015 0 1 + -0.79816624498824 0.28144460265207 0 1 + -0.70222473722653 0.32138804675313 0 1 + -0.70901834418913 0.41134983187753 0 1 + -0.77835425122081 0.41668568803658 0 1 + -0.74007153023893 0.36886618294704 0 1 + -0.78975244443614 0.50687981955638 0 1 + -0.81754265112946 0.46508922060496 0 1 + -0.6958857335558 0.13859122813591 0 1 + -0.69796886091544 0.23044387336366 0 1 + -0.73013030333241 0.18592974922511 0 1 + -0.62518523777152 0.13651532494811 0 1 + -0.66088061137097 0.09174068291428 0 1 + -0.55095661933911 0.22444939256248 0 1 + -0.62661277822576 0.22720731767544 0 1 + -0.58835057177959 0.18067935140395 0 1 + -0.63006791357564 0.31734141211163 0 1 + -0.66443222299592 0.27416536573157 0 1 + -0.5536416404972 0.31352095962838 0 1 + -0.55799522649559 0.40138439855525 0 1 + -0.63525112032543 0.40603332139213 0 1 + -0.59441073843259 0.35965895774879 0 1 + -0.47393537535527 0.3105621283871 0 1 + -0.51268757475873 0.26770872040857 0 1 + -0.4774393720023 0.39735110221589 0 1 + -0.43440313751772 0.35271671659756 0 1 + -0.56366391709668 0.48715998520443 0 1 + -0.52047629415509 0.44215268476449 0 1 + -0.71766660967817 0.49965490694383 0 1 + -0.72860978800367 0.58659907711068 0 1 + -0.75996778222674 0.547325758093 0 1 + -0.64237507109367 0.49314183839911 0 1 + -0.67623783521392 0.45265602333179 0 1 + -0.650839738787 0.57801262557342 0 1 + -0.60703419010782 0.53238000128002 0 1 + -0.6954594164517 0.62438932750491 0 1 + 0.048917591615598 -0.98066956681444 0 1 + -0.048917582553802 -0.9806695672675 0 1 + 4.6037790603656E-09 -0.98991976904934 0 1 + 0.14587825785864 -0.95808346114175 0 1 + 0.048613075068484 -0.95180829686158 0 1 + 0.097557412922795 -0.97013250752502 0 1 + 0.048324247930261 -0.91455210585572 0 1 + -0.04832423978775 -0.91455210628649 0 1 + -0.048613066450318 -0.95180829729986 0 1 + 4.1901134537685E-09 -0.93342780020199 0 1 + -0.14587824923964 -0.9580834624519 0 1 + -0.097557404069047 -0.97013250841391 0 1 + 0.24103027660064 -0.92800728162723 0 1 + 0.14475079551015 -0.91879446385888 0 1 + 0.19370456166032 -0.94393771321254 0 1 + 0.33350927767175 -0.88998498622129 0 1 + 0.23879462532813 -0.8793320645779 0 1 + 0.28763196067611 -0.90992256440146 0 1 + 0.23650127418358 -0.82500176995635 0 1 + 0.14227486040709 -0.81994019642477 0 1 + 0.14362970240151 -0.87268882568961 0 1 + 0.1903873347064 -0.84951660374406 0 1 + 0.047891086683544 -0.86946026417363 0 1 + 0.096177158687775 -0.89414935883847 0 1 + 0.047538668093173 -0.81749709573995 0 1 + -0.047538660938848 -0.81749709616293 0 1 + -0.047891079025574 -0.86946026459853 0 1 + 3.7026039355554E-09 -0.84380660076017 0 1 + 0.14075886005553 -0.7611314895792 0 1 + 0.046953843175623 -0.75945304328343 0 1 + 0.094453626717498 -0.78987417934197 0 1 + 0.046376663244129 -0.69555465259488 0 1 + -0.046376657177304 -0.69555465301634 0 1 + -0.046953836549922 -0.75945304370549 0 1 + 3.1725875678855E-09 -0.72798864700871 0 1 + -0.14075885338773 -0.76113149084717 0 1 + -0.142274853215 -0.8199401976941 0 1 + -0.094453619808755 -0.78987418018719 0 1 + -0.14475078734787 -0.91879446514549 0 1 + -0.24103026839819 -0.92800728375966 0 1 + -0.19370455325645 -0.94393771493591 0 1 + -0.14362969471397 -0.87268882696428 0 1 + -0.096177150776008 -0.89414935969263 0 1 + -0.23650126690977 -0.82500177207491 0 1 + -0.23879461757598 -0.87933206669775 0 1 + -0.19038732723136 -0.84951660543915 0 1 + -0.33350926981471 -0.88998498918001 0 1 + -0.28763195266127 -0.90992256694196 0 1 + 0.42227758545161 -0.84365732766134 0 1 + 0.32964089940003 -0.83249865584705 0 1 + 0.37833924901988 -0.86772436083377 0 1 + 0.50687982770007 -0.78975243928328 0 1 + 0.41668569644253 -0.77835424706513 0 1 + 0.46508922938571 -0.81754264635713 0 1 + 0.4113498316865 -0.70901833686139 0 1 + 0.32138805263827 -0.70222473348194 0 1 + 0.3256500004095 -0.76997425279581 0 1 + 0.36886619017064 -0.74007152632833 0 1 + 0.23356230833178 -0.76422437652184 0 1 + 0.28144461189696 -0.79816624229783 0 1 + 0.58659907659664 -0.72860977899144 0 1 + 0.49965490270585 -0.71766659975835 0 1 + 0.5473257638908 -0.75996777597816 0 1 + 0.66082283245263 -0.66082283378599 0 1 + 0.5780124716849 -0.65083967081346 0 1 + 0.62438930997451 -0.6954594012792 0 1 + 0.57058916571108 -0.57058933704308 0 1 + 0.48715788537523 -0.56366309758784 0 1 + 0.493141532912 -0.64237493255355 0 1 + 0.53237922169898 -0.60703388878184 0 1 + 0.40603316355666 -0.63525104435078 0 1 + 0.4526559596567 -0.67623780002198 0 1 + 0.40138409250741 -0.55799508914167 0 1 + 0.31352095427678 -0.55364163302318 0 1 + 0.31734141137088 -0.6300679075015 0 1 + 0.35965889351745 -0.59441070446216 0 1 + 0.48208789108499 -0.48208806303062 0 1 + 0.39735094719816 -0.47743930632685 0 1 + 0.44215190462431 -0.52047599397667 0 1 + 0.39420311848014 -0.39420312171691 0 1 + 0.30826214819948 -0.39136456664459 0 1 + 0.31056212612767 -0.47393536990149 0 1 + 0.35271669716047 -0.43440312573522 0 1 + 0.22223112627029 -0.47151364898768 0 1 + 0.2244493990523 -0.55095661795715 0 1 + 0.26770872451953 -0.51268757218162 0 1 + 0.23044388153956 -0.69796885911186 0 1 + 0.13859123660741 -0.69588573283679 0 1 + 0.18592975795272 -0.73013030196082 0 1 + 0.22720732499689 -0.62661277663294 0 1 + 0.27416537241346 -0.66443222036558 0 1 + 0.13460107666223 -0.54960295879175 0 1 + 0.13651533263747 -0.62518523726807 0 1 + 0.18067935855479 -0.58835057085795 0 1 + 0.045416956723334 -0.625113764413 0 1 + 0.091740691118551 -0.66088061129526 0 1 + 0.044901494053176 -0.54898603299981 0 1 + -0.044901489197826 -0.54898603341769 0 1 + -0.045416951246757 -0.62511376483267 0 1 + 2.5825613678795E-09 -0.58745848933374 0 1 + 0.13345649850677 -0.46994281078978 0 1 + 0.04446177436645 -0.46914680762052 0 1 + 0.089319034190852 -0.50964473367276 0 1 + 0.044261387705071 -0.38682860003498 0 1 + -0.044261384179467 -0.38682860044884 0 1 + -0.044461770162347 -0.4691468080361 0 1 + 1.9323998179118E-09 -0.42810076126178 0 1 + -0.13345649427294 -0.4699428120373 0 1 + -0.13460107177201 -0.54960296004618 0 1 + -0.089319029645019 -0.50964473450638 0 1 + 0.22088099988965 -0.38916545096705 0 1 + 0.13267621817934 -0.38761698811924 0 1 + 0.17730292285354 -0.42970032197666 0 1 + 0.30653087933455 -0.30653087882658 0 1 + 0.21980104221117 -0.30478065430177 0 1 + 0.26396095536584 -0.34809590177056 0 1 + 0.2189211044039 -0.21892110449294 0 1 + 0.13175669834039 -0.21798123155488 0 1 + 0.13220409193049 -0.3034981328061 0 1 + 0.17574153500801 -0.26138464840467 0 1 + 0.044101612489619 -0.30278504958799 0 1 + 0.088321008320233 -0.34525484417475 0 1 + 0.043995039710859 -0.21743046790296 0 1 + -0.043995037624609 -0.21743046831215 0 1 + -0.044101609670067 -0.30278504999957 0 1 + 1.2269153832795E-09 -0.26015635091447 0 1 + 0.13135698690854 -0.13135698763755 0 1 + 0.043857799898762 -0.13099114583065 0 1 + 0.087783953774113 -0.17449735726149 0 1 + 0.043778701506967 -0.043778702923678 0 1 + -0.043857798572324 -0.13099114623541 0 1 + 4.6876286170166E-10 -0.087415577767644 0 1 + -0.13175669624117 -0.21798123277785 0 1 + -0.087783952061077 -0.17449735807446 0 1 + -0.13267621463018 -0.38761698935921 0 1 + -0.22088099634697 -0.38916545305197 0 1 + -0.22223112211017 -0.47151365112141 0 1 + -0.17730291895074 -0.42970032364013 0 1 + -0.13220408909174 -0.30349813403898 0 1 + -0.088321005136197 -0.3452548449997 0 1 + -0.21980103934955 -0.30478065635052 0 1 + -0.17574153252452 -0.26138465003834 0 1 + -0.3082621466032 -0.39136457033663 0 1 + -0.26396095232303 -0.34809590431326 0 1 + -0.32964089197789 -0.83249865882573 0 1 + -0.42227757780072 -0.84365733151932 0 1 + -0.37833924126562 -0.86772436423815 0 1 + -0.23356230157975 -0.76422437864611 0 1 + -0.32564999355397 -0.7699742558006 0 1 + -0.28144460481097 -0.79816624484966 0 1 + -0.32138804841544 -0.70222473739275 0 1 + -0.41134983315723 -0.70901834422141 0 1 + -0.41668568948465 -0.77835425096649 0 1 + -0.36886618450575 -0.74007153019778 0 1 + -0.50687982057401 -0.78975244406925 0 1 + -0.46508922193137 -0.81754265065092 0 1 + -0.1385912304954 -0.6958857341033 0 1 + -0.23044387538893 -0.6979688612521 0 1 + -0.18592975152233 -0.73013030365569 0 1 + -0.13651532711849 -0.62518523853013 0 1 + -0.091740685325546 -0.66088061213745 0 1 + -0.22444939426329 -0.55095662012668 0 1 + -0.22720731952649 -0.62661277879731 0 1 + -0.18067935333642 -0.58835057254788 0 1 + -0.31734141361527 -0.63006791399124 0 1 + -0.27416536749123 -0.66443222336649 0 1 + -0.31352096100804 -0.55364164114646 0 1 + -0.40138439960601 -0.55799522704287 0 1 + -0.40603332254457 -0.63525112062474 0 1 + -0.3596589590177 -0.59441073890825 0 1 + -0.3105621296654 -0.47393537621876 0 1 + -0.26770872189117 -0.51268757557852 0 1 + -0.39735110320053 -0.47743937278967 0 1 + -0.35271671770046 -0.43440313844899 0 1 + -0.48715998593856 -0.56366391758822 0 1 + -0.44215268562642 -0.52047629479627 0 1 + -0.49965490784443 -0.71766660961786 0 1 + -0.586599077631 -0.72860978788655 0 1 + -0.54732575884867 -0.75996778197895 0 1 + -0.49314183920127 -0.64237507131518 0 1 + -0.45265602436254 -0.67623783533521 0 1 + -0.5780126260387 -0.65083973897423 0 1 + -0.53238000188358 -0.60703419044896 0 1 + -0.62438932781785 -0.69545941648125 0 1 + 0.98066956695022 0.048917587475784 0 1 + 0.98066956697836 -0.048917586930597 0 1 + 0.98991976900946 1.846122800648E-10 0 1 + 0.95808346154399 0.14587825439834 0 1 + 0.95180829687265 0.048613071291431 0 1 + 0.97013250780819 0.09755740910985 0 1 + 0.91455210572979 0.048324244480448 0 1 + 0.91455210579188 -0.048324243516407 0 1 + 0.95180829692055 -0.04861307049484 0 1 + 0.93342779995641 4.4008944964708E-10 0 1 + 0.95808346168912 -0.14587825352044 0 1 + 0.97013250788612 -0.097557408393429 0 1 + 0.92800728218282 0.24103027382321 0 1 + 0.91879446408182 0.14475079237699 0 1 + 0.94393771370029 0.19370455855903 0 1 + 0.88998498685245 0.33350927546549 0 1 + 0.87933206492861 0.23879462278881 0 1 + 0.90992256500429 0.28763195819205 0 1 + 0.82500177010836 0.23650127186179 0 1 + 0.81994019629741 0.14227485778317 0 1 + 0.87268882573898 0.1436296995419 0 1 + 0.84951660385278 0.1903873321219 0 1 + 0.86946026389583 0.047891083520365 0 1 + 0.8941493588078 0.096177155536793 0 1 + 0.81749709530824 0.047538665182485 0 1 + 0.8174970954033 -0.047538664118069 0 1 + 0.86946026397703 -0.047891082466147 0 1 + 0.84380660023936 5.2975070607382E-10 0 1 + 0.76113148927544 0.14075885763715 0 1 + 0.7594530426941 0.046953840484184 0 1 + 0.78987417898165 0.094453624057888 0 1 + 0.69555465184989 0.046376660743602 0 1 + 0.69555465198303 -0.04637665991602 0 1 + 0.75945304280933 -0.046953839493779 0 1 + 0.72798864619486 4.5476739387779E-10 0 1 + 0.76113148962653 -0.14075885656151 0 1 + 0.81994019659656 -0.14227485663441 0 1 + 0.78987417919442 -0.094453622987765 0 1 + 0.91879446427963 -0.1447507913358 0 1 + 0.92800728252161 -0.24103027264365 0 1 + 0.94393771393591 -0.19370455751732 0 1 + 0.87268882598457 -0.14362969841026 0 1 + 0.89414935895327 -0.096177154489538 0 1 + 0.82500177063477 -0.23650127053944 0 1 + 0.87933206536532 -0.23879462149226 0 1 + 0.8495166042268 -0.19038733089714 0 1 + 0.8899849875096 -0.33350927390062 0 1 + 0.90992256548443 -0.28763195683356 0 1 + 0.84365732828384 0.42227758375312 0 1 + 0.83249865624484 0.32964089738349 0 1 + 0.86772436147174 0.37833924706911 0 1 + 0.78975243980683 0.50687982648696 0 1 + 0.7783542474247 0.4166856949059 0 1 + 0.81754264693343 0.46508922794422 0 1 + 0.7090183369778 0.41134983028079 0 1 + 0.7022247334249 0.32138805093878 0 1 + 0.76997425296486 0.32564999856495 0 1 + 0.74007152647735 0.36886618855015 0 1 + 0.7642243764675 0.23356230619431 0 1 + 0.79816624246643 0.28144460981852 0 1 + 0.72860977936114 0.58659907578871 0 1 + 0.71766660001348 0.49965490159705 0 1 + 0.75996777643499 0.5473257628832 0 1 + 0.65083967088168 0.57801247095846 0 1 + 0.69545940153705 0.62438930935499 0 1 + 0.56366309732458 0.4871578844282 0 1 + 0.64237493254971 0.4931415318964 0 1 + 0.60703388867939 0.53237922086224 0 1 + 0.63525104423064 0.40603316225547 0 1 + 0.67623780008641 0.45265595845045 0 1 + 0.55799508879518 0.40138409128872 0 1 + 0.55364163254355 0.3135209527903 0 1 + 0.6300679072296 0.3173414097911 0 1 + 0.59441070416048 0.35965889212249 0 1 + 0.47743930575174 0.39735094603264 0 1 + 0.52047599355509 0.44215190356687 0 1 + 0.39136456577182 0.30826214682531 0 1 + 0.47393536922642 0.31056212471324 0 1 + 0.43440312500913 0.35271669588899 0 1 + 0.4715136481629 0.22223112461083 0 1 + 0.55095661731007 0.22444939730852 0 1 + 0.51268757152747 0.26770872294466 0 1 + 0.69796885885329 0.23044387955906 0 1 + 0.69588573234709 0.13859123435826 0 1 + 0.73013030168688 0.18592975575795 0 1 + 0.62661277617378 0.22720732314566 0 1 + 0.66443222010576 0.27416537063689 0 1 + 0.54960295794612 0.1346010746743 0 1 + 0.62518523659721 0.13651533053153 0 1 + 0.58835057020346 0.18067935663291 0 1 + 0.62511376350475 0.045416954379869 0 1 + 0.66088061059396 0.091740688819608 0 1 + 0.54898603193539 0.044901491844327 0 1 + 0.54898603211103 -0.044901491607849 0 1 + 0.62511376366586 -0.045416953804893 0 1 + 0.58745848822403 2.0303035420744E-10 0 1 + 0.46994280978442 0.13345649661835 0 1 + 0.46914680640786 0.044461772267089 0 1 + 0.50964473264163 0.089319032144795 0 1 + 0.38682859868806 0.044261385692761 0 1 + 0.38682859888561 -0.04426138637024 0 1 + 0.46914680659654 -0.04446177244962 0 1 + 0.42810075987175 -2.1500272056993E-10 0 1 + 0.46994281035057 -0.13345649672613 0 1 + 0.54960295847777 -0.13460107436087 0 1 + 0.50964473300733 -0.089319032079405 0 1 + 0.38916544997621 0.22088099829237 0 1 + 0.38761698696443 0.13267621636566 0 1 + 0.42970032098498 0.17730292111494 0 1 + 0.30478065313996 0.21980104063884 0 1 + 0.34809590075108 0.2639609538907 0 1 + 0.21798123011973 0.13175669658455 0 1 + 0.3034981315124 0.13220409016501 0 1 + 0.26138464710338 0.17574153334147 0 1 + 0.30278504811865 0.04410161053863 0 1 + 0.34525484286045 0.088321006435673 0 1 + 0.2174304663259 0.043995037796949 0 1 + 0.21743046655903 -0.043995039680686 0 1 + 0.30278504833079 -0.04410161178432 0 1 + 0.26015634929739 -7.8251382758146E-10 0 1 + 0.13099114415186 0.043857797988985 0 1 + 0.17449735569776 0.087783951934935 0 1 + 0.13099114443484 -0.043857800575246 0 1 + 0.087415576002872 -1.4835646241419E-09 0 1 + 0.21798123084287 -0.13175669839839 0 1 + 0.17449735621284 -0.087783954135784 0 1 + 0.38761698756517 -0.13267621697081 0 1 + 0.3891654510153 -0.22088099880617 0 1 + 0.47151364917455 -0.22223112470009 0 1 + 0.42970032177342 -0.17730292141281 0 1 + 0.30349813215551 -0.13220409133963 0 1 + 0.34525484327109 -0.088321007361277 0 1 + 0.30478065425416 -0.2198010416838 0 1 + 0.26138464802539 -0.17574153476756 0 1 + 0.39136456806024 -0.30826214913397 0 1 + 0.34809590212953 -0.26396095475259 0 1 + 0.83249865704805 -0.32964089578673 0 1 + 0.8436573293993 -0.42227758177499 0 1 + 0.86772436234764 -0.37833924528674 0 1 + 0.76422437709679 -0.23356230495445 0 1 + 0.7699742539193 -0.32564999710396 0 1 + 0.79816624318687 -0.28144460840262 0 1 + 0.70222473541874 -0.32138805171829 0 1 + 0.70901834193038 -0.41134983658491 0 1 + 0.77835424875574 -0.41668569317714 0 1 + 0.74007152810718 -0.36886618800088 0 1 + 0.78975244152619 -0.50687982437988 0 1 + 0.81754264831586 -0.46508922582832 0 1 + 0.69588573276538 -0.13859123344777 0 1 + 0.69796885959681 -0.23044387853218 0 1 + 0.73013030221491 -0.18592975468372 0 1 + 0.62518523707571 -0.13651532987627 0 1 + 0.66088061089098 -0.091740688076781 0 1 + 0.55095661827405 -0.22444939701179 0 1 + 0.62661277704294 -0.22720732245871 0 1 + 0.58835057089145 -0.18067935609312 0 1 + 0.63006791193047 -0.31734141669288 0 1 + 0.66443222150478 -0.2741653706064 0 1 + 0.55364163900716 -0.31352096387958 0 1 + 0.55799522462133 -0.4013844025588 0 1 + 0.63525111826679 -0.40603332572133 0 1 + 0.59441073666192 -0.35965896203953 0 1 + 0.47393537400257 -0.31056213235954 0 1 + 0.51268757353919 -0.2677087246186 0 1 + 0.47743937031549 -0.39735110594744 0 1 + 0.43440313607606 -0.35271672033659 0 1 + 0.56366391490115 -0.48715998891865 0 1 + 0.52047629221729 -0.44215268848803 0 1 + 0.71766660702299 -0.49965491134522 0 1 + 0.72860978499379 -0.58659908116075 0 1 + 0.75996777925541 -0.54732576252284 0 1 + 0.6423750686706 -0.49314184243008 0 1 + 0.67623783286136 -0.45265602769844 0 1 + 0.65083973606383 -0.57801262926211 0 1 + 0.60703418765211 -0.53238000498359 0 1 + 0.69545941345001 -0.62438933117058 0 1 + Edges + 128 + 2 3 1000 + 3 4 1000 + 4 5 1000 + 5 6 1000 + 6 7 1000 + 7 8 1000 + 8 9 1000 + 9 10 1000 + 10 11 1000 + 11 12 1000 + 12 13 1000 + 13 14 1000 + 14 15 1000 + 15 16 1000 + 16 17 1000 + 17 18 1000 + 18 19 1000 + 19 20 1000 + 20 21 1000 + 21 22 1000 + 22 23 1000 + 23 24 1000 + 24 25 1000 + 25 26 1000 + 26 27 1000 + 27 28 1000 + 28 29 1000 + 29 30 1000 + 30 31 1000 + 31 32 1000 + 32 33 1000 + 33 34 1000 + 34 35 1000 + 35 36 1000 + 36 37 1000 + 37 38 1000 + 38 39 1000 + 39 40 1000 + 40 41 1000 + 41 42 1000 + 42 43 1000 + 43 44 1000 + 44 45 1000 + 45 46 1000 + 46 47 1000 + 47 48 1000 + 48 49 1000 + 49 50 1000 + 50 51 1000 + 51 52 1000 + 52 53 1000 + 53 54 1000 + 54 55 1000 + 55 56 1000 + 56 57 1000 + 57 58 1000 + 58 59 1000 + 59 60 1000 + 60 61 1000 + 61 62 1000 + 62 63 1000 + 63 64 1000 + 64 65 1000 + 65 66 1000 + 66 67 1000 + 67 68 1000 + 68 69 1000 + 69 70 1000 + 70 71 1000 + 71 72 1000 + 72 73 1000 + 73 74 1000 + 74 75 1000 + 75 76 1000 + 76 77 1000 + 77 78 1000 + 78 79 1000 + 79 80 1000 + 80 81 1000 + 81 82 1000 + 82 83 1000 + 83 84 1000 + 84 85 1000 + 85 86 1000 + 86 87 1000 + 87 88 1000 + 88 89 1000 + 89 90 1000 + 90 91 1000 + 91 92 1000 + 92 93 1000 + 93 94 1000 + 94 95 1000 + 95 96 1000 + 96 97 1000 + 97 98 1000 + 98 99 1000 + 99 100 1000 + 100 101 1000 + 101 102 1000 + 102 103 1000 + 103 104 1000 + 104 105 1000 + 105 106 1000 + 106 107 1000 + 107 108 1000 + 108 109 1000 + 109 110 1000 + 110 111 1000 + 111 112 1000 + 112 113 1000 + 113 114 1000 + 114 115 1000 + 115 116 1000 + 116 117 1000 + 117 118 1000 + 118 119 1000 + 119 120 1000 + 120 121 1000 + 121 122 1000 + 122 123 1000 + 123 124 1000 + 124 125 1000 + 125 126 1000 + 126 127 1000 + 127 128 1000 + 128 129 1000 + 129 2 1000 + Quadrilaterals + 1024 + 34 35 357 33 0 + 35 36 355 357 0 + 357 355 181 356 0 + 33 357 356 32 0 + 36 37 360 355 0 + 37 38 358 360 0 + 360 358 179 359 0 + 355 360 359 181 0 + 181 359 364 363 0 + 359 179 361 364 0 + 364 361 141 362 0 + 363 364 362 180 0 + 32 356 366 31 0 + 356 181 363 366 0 + 366 363 180 365 0 + 31 366 365 30 0 + 38 39 369 358 0 + 39 40 367 369 0 + 369 367 184 368 0 + 358 369 368 179 0 + 40 41 372 367 0 + 41 42 370 372 0 + 372 370 182 371 0 + 367 372 371 184 0 + 184 371 376 375 0 + 371 182 373 376 0 + 376 373 139 374 0 + 375 376 374 183 0 + 179 368 378 361 0 + 368 184 375 378 0 + 378 375 183 377 0 + 361 378 377 141 0 + 141 377 382 381 0 + 377 183 379 382 0 + 382 379 188 380 0 + 381 382 380 187 0 + 183 374 385 379 0 + 374 139 383 385 0 + 385 383 185 384 0 + 379 385 384 188 0 + 188 384 389 388 0 + 384 185 386 389 0 + 389 386 133 387 0 + 388 389 387 186 0 + 187 380 392 391 0 + 380 188 388 392 0 + 392 388 186 390 0 + 391 392 390 140 0 + 30 365 395 29 0 + 365 180 393 395 0 + 395 393 190 394 0 + 29 395 394 28 0 + 180 362 397 393 0 + 362 141 381 397 0 + 397 381 187 396 0 + 393 397 396 190 0 + 190 396 400 399 0 + 396 187 391 400 0 + 400 391 140 398 0 + 399 400 398 189 0 + 28 394 402 27 0 + 394 190 399 402 0 + 402 399 189 401 0 + 27 402 401 26 0 + 42 43 405 370 0 + 43 44 403 405 0 + 405 403 193 404 0 + 370 405 404 182 0 + 44 45 408 403 0 + 45 46 406 408 0 + 408 406 191 407 0 + 403 408 407 193 0 + 193 407 412 411 0 + 407 191 409 412 0 + 412 409 144 410 0 + 411 412 410 192 0 + 182 404 414 373 0 + 404 193 411 414 0 + 414 411 192 413 0 + 373 414 413 139 0 + 46 47 417 406 0 + 47 48 415 417 0 + 417 415 196 416 0 + 406 417 416 191 0 + 48 49 420 415 0 + 49 50 418 420 0 + 420 418 194 419 0 + 415 420 419 196 0 + 196 419 424 423 0 + 419 194 421 424 0 + 424 421 142 422 0 + 423 424 422 195 0 + 191 416 426 409 0 + 416 196 423 426 0 + 426 423 195 425 0 + 409 426 425 144 0 + 144 425 430 429 0 + 425 195 427 430 0 + 430 427 200 428 0 + 429 430 428 199 0 + 195 422 433 427 0 + 422 142 431 433 0 + 433 431 197 432 0 + 427 433 432 200 0 + 200 432 437 436 0 + 432 197 434 437 0 + 437 434 131 435 0 + 436 437 435 198 0 + 199 428 440 439 0 + 428 200 436 440 0 + 440 436 198 438 0 + 439 440 438 143 0 + 139 413 443 383 0 + 413 192 441 443 0 + 443 441 202 442 0 + 383 443 442 185 0 + 192 410 445 441 0 + 410 144 429 445 0 + 445 429 199 444 0 + 441 445 444 202 0 + 202 444 448 447 0 + 444 199 439 448 0 + 448 439 143 446 0 + 447 448 446 201 0 + 185 442 450 386 0 + 442 202 447 450 0 + 450 447 201 449 0 + 386 450 449 133 0 + 133 449 454 453 0 + 449 201 451 454 0 + 454 451 206 452 0 + 453 454 452 205 0 + 201 446 457 451 0 + 446 143 455 457 0 + 457 455 203 456 0 + 451 457 456 206 0 + 206 456 461 460 0 + 456 203 458 461 0 + 461 458 148 459 0 + 460 461 459 204 0 + 205 452 464 463 0 + 452 206 460 464 0 + 464 460 204 462 0 + 463 464 462 147 0 + 143 438 467 455 0 + 438 198 465 467 0 + 467 465 209 466 0 + 455 467 466 203 0 + 198 435 470 465 0 + 435 131 468 470 0 + 470 468 207 469 0 + 465 470 469 209 0 + 209 469 474 473 0 + 469 207 471 474 0 + 474 471 145 472 0 + 473 474 472 208 0 + 203 466 476 458 0 + 466 209 473 476 0 + 476 473 208 475 0 + 458 476 475 148 0 + 148 475 480 479 0 + 475 208 477 480 0 + 480 477 213 478 0 + 479 480 478 212 0 + 208 472 483 477 0 + 472 145 481 483 0 + 483 481 210 482 0 + 477 483 482 213 0 + 213 482 487 486 0 + 482 210 484 487 0 + 487 484 130 485 0 + 486 487 485 211 0 + 212 478 490 489 0 + 478 213 486 490 0 + 490 486 211 488 0 + 489 490 488 146 0 + 147 462 494 493 0 + 462 204 491 494 0 + 494 491 216 492 0 + 493 494 492 215 0 + 204 459 496 491 0 + 459 148 479 496 0 + 496 479 212 495 0 + 491 496 495 216 0 + 216 495 499 498 0 + 495 212 489 499 0 + 499 489 146 497 0 + 498 499 497 214 0 + 215 492 502 501 0 + 492 216 498 502 0 + 502 498 214 500 0 + 501 502 500 132 0 + 26 401 505 25 0 + 401 189 503 505 0 + 505 503 219 504 0 + 25 505 504 24 0 + 189 398 508 503 0 + 398 140 506 508 0 + 508 506 217 507 0 + 503 508 507 219 0 + 219 507 512 511 0 + 507 217 509 512 0 + 512 509 150 510 0 + 511 512 510 218 0 + 24 504 514 23 0 + 504 219 511 514 0 + 514 511 218 513 0 + 23 514 513 22 0 + 140 390 517 506 0 + 390 186 515 517 0 + 517 515 221 516 0 + 506 517 516 217 0 + 186 387 519 515 0 + 387 133 453 519 0 + 519 453 205 518 0 + 515 519 518 221 0 + 221 518 522 521 0 + 518 205 463 522 0 + 522 463 147 520 0 + 521 522 520 220 0 + 217 516 524 509 0 + 516 221 521 524 0 + 524 521 220 523 0 + 509 524 523 150 0 + 150 523 528 527 0 + 523 220 525 528 0 + 528 525 224 526 0 + 527 528 526 223 0 + 220 520 530 525 0 + 520 147 493 530 0 + 530 493 215 529 0 + 525 530 529 224 0 + 224 529 533 532 0 + 529 215 501 533 0 + 533 501 132 531 0 + 532 533 531 222 0 + 223 526 536 535 0 + 526 224 532 536 0 + 536 532 222 534 0 + 535 536 534 149 0 + 22 513 539 21 0 + 513 218 537 539 0 + 539 537 226 538 0 + 21 539 538 20 0 + 218 510 541 537 0 + 510 150 527 541 0 + 541 527 223 540 0 + 537 541 540 226 0 + 226 540 544 543 0 + 540 223 535 544 0 + 544 535 149 542 0 + 543 544 542 225 0 + 20 538 546 19 0 + 538 226 543 546 0 + 546 543 225 545 0 + 19 546 545 18 0 + 66 67 549 65 0 + 67 68 547 549 0 + 549 547 229 548 0 + 65 549 548 64 0 + 68 69 552 547 0 + 69 70 550 552 0 + 552 550 227 551 0 + 547 552 551 229 0 + 229 551 556 555 0 + 551 227 553 556 0 + 556 553 153 554 0 + 555 556 554 228 0 + 64 548 558 63 0 + 548 229 555 558 0 + 558 555 228 557 0 + 63 558 557 62 0 + 70 71 561 550 0 + 71 72 559 561 0 + 561 559 232 560 0 + 550 561 560 227 0 + 72 73 564 559 0 + 73 74 562 564 0 + 564 562 230 563 0 + 559 564 563 232 0 + 232 563 568 567 0 + 563 230 565 568 0 + 568 565 151 566 0 + 567 568 566 231 0 + 227 560 570 553 0 + 560 232 567 570 0 + 570 567 231 569 0 + 553 570 569 153 0 + 153 569 574 573 0 + 569 231 571 574 0 + 574 571 236 572 0 + 573 574 572 235 0 + 231 566 577 571 0 + 566 151 575 577 0 + 577 575 233 576 0 + 571 577 576 236 0 + 236 576 581 580 0 + 576 233 578 581 0 + 581 578 135 579 0 + 580 581 579 234 0 + 235 572 584 583 0 + 572 236 580 584 0 + 584 580 234 582 0 + 583 584 582 152 0 + 62 557 587 61 0 + 557 228 585 587 0 + 587 585 238 586 0 + 61 587 586 60 0 + 228 554 589 585 0 + 554 153 573 589 0 + 589 573 235 588 0 + 585 589 588 238 0 + 238 588 592 591 0 + 588 235 583 592 0 + 592 583 152 590 0 + 591 592 590 237 0 + 60 586 594 59 0 + 586 238 591 594 0 + 594 591 237 593 0 + 59 594 593 58 0 + 74 75 597 562 0 + 75 76 595 597 0 + 597 595 241 596 0 + 562 597 596 230 0 + 76 77 600 595 0 + 77 78 598 600 0 + 600 598 239 599 0 + 595 600 599 241 0 + 241 599 604 603 0 + 599 239 601 604 0 + 604 601 156 602 0 + 603 604 602 240 0 + 230 596 606 565 0 + 596 241 603 606 0 + 606 603 240 605 0 + 565 606 605 151 0 + 78 79 609 598 0 + 79 80 607 609 0 + 609 607 244 608 0 + 598 609 608 239 0 + 80 81 612 607 0 + 81 82 610 612 0 + 612 610 242 611 0 + 607 612 611 244 0 + 244 611 616 615 0 + 611 242 613 616 0 + 616 613 154 614 0 + 615 616 614 243 0 + 239 608 618 601 0 + 608 244 615 618 0 + 618 615 243 617 0 + 601 618 617 156 0 + 156 617 622 621 0 + 617 243 619 622 0 + 622 619 248 620 0 + 621 622 620 247 0 + 243 614 625 619 0 + 614 154 623 625 0 + 625 623 245 624 0 + 619 625 624 248 0 + 248 624 629 628 0 + 624 245 626 629 0 + 629 626 134 627 0 + 628 629 627 246 0 + 247 620 632 631 0 + 620 248 628 632 0 + 632 628 246 630 0 + 631 632 630 155 0 + 151 605 635 575 0 + 605 240 633 635 0 + 635 633 250 634 0 + 575 635 634 233 0 + 240 602 637 633 0 + 602 156 621 637 0 + 637 621 247 636 0 + 633 637 636 250 0 + 250 636 640 639 0 + 636 247 631 640 0 + 640 631 155 638 0 + 639 640 638 249 0 + 233 634 642 578 0 + 634 250 639 642 0 + 642 639 249 641 0 + 578 642 641 135 0 + 135 641 646 645 0 + 641 249 643 646 0 + 646 643 254 644 0 + 645 646 644 253 0 + 249 638 649 643 0 + 638 155 647 649 0 + 649 647 251 648 0 + 643 649 648 254 0 + 254 648 653 652 0 + 648 251 650 653 0 + 653 650 159 651 0 + 652 653 651 252 0 + 253 644 656 655 0 + 644 254 652 656 0 + 656 652 252 654 0 + 655 656 654 158 0 + 155 630 659 647 0 + 630 246 657 659 0 + 659 657 257 658 0 + 647 659 658 251 0 + 246 627 662 657 0 + 627 134 660 662 0 + 662 660 255 661 0 + 657 662 661 257 0 + 257 661 666 665 0 + 661 255 663 666 0 + 666 663 157 664 0 + 665 666 664 256 0 + 251 658 668 650 0 + 658 257 665 668 0 + 668 665 256 667 0 + 650 668 667 159 0 + 159 667 672 671 0 + 667 256 669 672 0 + 672 669 260 670 0 + 671 672 670 259 0 + 256 664 675 669 0 + 664 157 673 675 0 + 675 673 258 674 0 + 669 675 674 260 0 + 260 674 678 677 0 + 674 258 676 678 0 + 678 676 130 484 0 + 677 678 484 210 0 + 259 670 680 679 0 + 670 260 677 680 0 + 680 677 210 481 0 + 679 680 481 145 0 + 158 654 684 683 0 + 654 252 681 684 0 + 684 681 262 682 0 + 683 684 682 261 0 + 252 651 686 681 0 + 651 159 671 686 0 + 686 671 259 685 0 + 681 686 685 262 0 + 262 685 688 687 0 + 685 259 679 688 0 + 688 679 145 471 0 + 687 688 471 207 0 + 261 682 690 689 0 + 682 262 687 690 0 + 690 687 207 468 0 + 689 690 468 131 0 + 58 593 693 57 0 + 593 237 691 693 0 + 693 691 265 692 0 + 57 693 692 56 0 + 237 590 696 691 0 + 590 152 694 696 0 + 696 694 263 695 0 + 691 696 695 265 0 + 265 695 700 699 0 + 695 263 697 700 0 + 700 697 160 698 0 + 699 700 698 264 0 + 56 692 702 55 0 + 692 265 699 702 0 + 702 699 264 701 0 + 55 702 701 54 0 + 152 582 705 694 0 + 582 234 703 705 0 + 705 703 267 704 0 + 694 705 704 263 0 + 234 579 707 703 0 + 579 135 645 707 0 + 707 645 253 706 0 + 703 707 706 267 0 + 267 706 710 709 0 + 706 253 655 710 0 + 710 655 158 708 0 + 709 710 708 266 0 + 263 704 712 697 0 + 704 267 709 712 0 + 712 709 266 711 0 + 697 712 711 160 0 + 160 711 716 715 0 + 711 266 713 716 0 + 716 713 269 714 0 + 715 716 714 268 0 + 266 708 718 713 0 + 708 158 683 718 0 + 718 683 261 717 0 + 713 718 717 269 0 + 269 717 720 719 0 + 717 261 689 720 0 + 720 689 131 434 0 + 719 720 434 197 0 + 268 714 722 721 0 + 714 269 719 722 0 + 722 719 197 431 0 + 721 722 431 142 0 + 54 701 725 53 0 + 701 264 723 725 0 + 725 723 270 724 0 + 53 725 724 52 0 + 264 698 727 723 0 + 698 160 715 727 0 + 727 715 268 726 0 + 723 727 726 270 0 + 270 726 729 728 0 + 726 268 721 729 0 + 729 721 142 421 0 + 728 729 421 194 0 + 52 724 730 51 0 + 724 270 728 730 0 + 730 728 194 418 0 + 51 730 418 50 0 + 98 99 733 97 0 + 99 100 731 733 0 + 733 731 273 732 0 + 97 733 732 96 0 + 100 101 736 731 0 + 101 102 734 736 0 + 736 734 271 735 0 + 731 736 735 273 0 + 273 735 740 739 0 + 735 271 737 740 0 + 740 737 163 738 0 + 739 740 738 272 0 + 96 732 742 95 0 + 732 273 739 742 0 + 742 739 272 741 0 + 95 742 741 94 0 + 102 103 745 734 0 + 103 104 743 745 0 + 745 743 276 744 0 + 734 745 744 271 0 + 104 105 748 743 0 + 105 106 746 748 0 + 748 746 274 747 0 + 743 748 747 276 0 + 276 747 752 751 0 + 747 274 749 752 0 + 752 749 161 750 0 + 751 752 750 275 0 + 271 744 754 737 0 + 744 276 751 754 0 + 754 751 275 753 0 + 737 754 753 163 0 + 163 753 758 757 0 + 753 275 755 758 0 + 758 755 280 756 0 + 757 758 756 279 0 + 275 750 761 755 0 + 750 161 759 761 0 + 761 759 277 760 0 + 755 761 760 280 0 + 280 760 765 764 0 + 760 277 762 765 0 + 765 762 137 763 0 + 764 765 763 278 0 + 279 756 768 767 0 + 756 280 764 768 0 + 768 764 278 766 0 + 767 768 766 162 0 + 94 741 771 93 0 + 741 272 769 771 0 + 771 769 282 770 0 + 93 771 770 92 0 + 272 738 773 769 0 + 738 163 757 773 0 + 773 757 279 772 0 + 769 773 772 282 0 + 282 772 776 775 0 + 772 279 767 776 0 + 776 767 162 774 0 + 775 776 774 281 0 + 92 770 778 91 0 + 770 282 775 778 0 + 778 775 281 777 0 + 91 778 777 90 0 + 106 107 781 746 0 + 107 108 779 781 0 + 781 779 285 780 0 + 746 781 780 274 0 + 108 109 784 779 0 + 109 110 782 784 0 + 784 782 283 783 0 + 779 784 783 285 0 + 285 783 788 787 0 + 783 283 785 788 0 + 788 785 166 786 0 + 787 788 786 284 0 + 274 780 790 749 0 + 780 285 787 790 0 + 790 787 284 789 0 + 749 790 789 161 0 + 110 111 793 782 0 + 111 112 791 793 0 + 793 791 288 792 0 + 782 793 792 283 0 + 112 113 796 791 0 + 113 114 794 796 0 + 796 794 286 795 0 + 791 796 795 288 0 + 288 795 800 799 0 + 795 286 797 800 0 + 800 797 164 798 0 + 799 800 798 287 0 + 283 792 802 785 0 + 792 288 799 802 0 + 802 799 287 801 0 + 785 802 801 166 0 + 166 801 806 805 0 + 801 287 803 806 0 + 806 803 292 804 0 + 805 806 804 291 0 + 287 798 809 803 0 + 798 164 807 809 0 + 809 807 289 808 0 + 803 809 808 292 0 + 292 808 813 812 0 + 808 289 810 813 0 + 813 810 136 811 0 + 812 813 811 290 0 + 291 804 816 815 0 + 804 292 812 816 0 + 816 812 290 814 0 + 815 816 814 165 0 + 161 789 819 759 0 + 789 284 817 819 0 + 819 817 294 818 0 + 759 819 818 277 0 + 284 786 821 817 0 + 786 166 805 821 0 + 821 805 291 820 0 + 817 821 820 294 0 + 294 820 824 823 0 + 820 291 815 824 0 + 824 815 165 822 0 + 823 824 822 293 0 + 277 818 826 762 0 + 818 294 823 826 0 + 826 823 293 825 0 + 762 826 825 137 0 + 137 825 830 829 0 + 825 293 827 830 0 + 830 827 298 828 0 + 829 830 828 297 0 + 293 822 833 827 0 + 822 165 831 833 0 + 833 831 295 832 0 + 827 833 832 298 0 + 298 832 837 836 0 + 832 295 834 837 0 + 837 834 169 835 0 + 836 837 835 296 0 + 297 828 840 839 0 + 828 298 836 840 0 + 840 836 296 838 0 + 839 840 838 168 0 + 165 814 843 831 0 + 814 290 841 843 0 + 843 841 301 842 0 + 831 843 842 295 0 + 290 811 846 841 0 + 811 136 844 846 0 + 846 844 299 845 0 + 841 846 845 301 0 + 301 845 850 849 0 + 845 299 847 850 0 + 850 847 167 848 0 + 849 850 848 300 0 + 295 842 852 834 0 + 842 301 849 852 0 + 852 849 300 851 0 + 834 852 851 169 0 + 169 851 856 855 0 + 851 300 853 856 0 + 856 853 304 854 0 + 855 856 854 303 0 + 300 848 859 853 0 + 848 167 857 859 0 + 859 857 302 858 0 + 853 859 858 304 0 + 304 858 862 861 0 + 858 302 860 862 0 + 862 860 130 676 0 + 861 862 676 258 0 + 303 854 864 863 0 + 854 304 861 864 0 + 864 861 258 673 0 + 863 864 673 157 0 + 168 838 868 867 0 + 838 296 865 868 0 + 868 865 306 866 0 + 867 868 866 305 0 + 296 835 870 865 0 + 835 169 855 870 0 + 870 855 303 869 0 + 865 870 869 306 0 + 306 869 872 871 0 + 869 303 863 872 0 + 872 863 157 663 0 + 871 872 663 255 0 + 305 866 874 873 0 + 866 306 871 874 0 + 874 871 255 660 0 + 873 874 660 134 0 + 90 777 877 89 0 + 777 281 875 877 0 + 877 875 309 876 0 + 89 877 876 88 0 + 281 774 880 875 0 + 774 162 878 880 0 + 880 878 307 879 0 + 875 880 879 309 0 + 309 879 884 883 0 + 879 307 881 884 0 + 884 881 170 882 0 + 883 884 882 308 0 + 88 876 886 87 0 + 876 309 883 886 0 + 886 883 308 885 0 + 87 886 885 86 0 + 162 766 889 878 0 + 766 278 887 889 0 + 889 887 311 888 0 + 878 889 888 307 0 + 278 763 891 887 0 + 763 137 829 891 0 + 891 829 297 890 0 + 887 891 890 311 0 + 311 890 894 893 0 + 890 297 839 894 0 + 894 839 168 892 0 + 893 894 892 310 0 + 307 888 896 881 0 + 888 311 893 896 0 + 896 893 310 895 0 + 881 896 895 170 0 + 170 895 900 899 0 + 895 310 897 900 0 + 900 897 313 898 0 + 899 900 898 312 0 + 310 892 902 897 0 + 892 168 867 902 0 + 902 867 305 901 0 + 897 902 901 313 0 + 313 901 904 903 0 + 901 305 873 904 0 + 904 873 134 626 0 + 903 904 626 245 0 + 312 898 906 905 0 + 898 313 903 906 0 + 906 903 245 623 0 + 905 906 623 154 0 + 86 885 909 85 0 + 885 308 907 909 0 + 909 907 314 908 0 + 85 909 908 84 0 + 308 882 911 907 0 + 882 170 899 911 0 + 911 899 312 910 0 + 907 911 910 314 0 + 314 910 913 912 0 + 910 312 905 913 0 + 913 905 154 613 0 + 912 913 613 242 0 + 84 908 914 83 0 + 908 314 912 914 0 + 914 912 242 610 0 + 83 914 610 82 0 + 2 3 917 129 0 + 3 4 915 917 0 + 917 915 317 916 0 + 129 917 916 128 0 + 4 5 920 915 0 + 5 6 918 920 0 + 920 918 315 919 0 + 915 920 919 317 0 + 317 919 924 923 0 + 919 315 921 924 0 + 924 921 173 922 0 + 923 924 922 316 0 + 128 916 926 127 0 + 916 317 923 926 0 + 926 923 316 925 0 + 127 926 925 126 0 + 6 7 929 918 0 + 7 8 927 929 0 + 929 927 320 928 0 + 918 929 928 315 0 + 8 9 932 927 0 + 9 10 930 932 0 + 932 930 318 931 0 + 927 932 931 320 0 + 320 931 936 935 0 + 931 318 933 936 0 + 936 933 171 934 0 + 935 936 934 319 0 + 315 928 938 921 0 + 928 320 935 938 0 + 938 935 319 937 0 + 921 938 937 173 0 + 173 937 942 941 0 + 937 319 939 942 0 + 942 939 324 940 0 + 941 942 940 323 0 + 319 934 945 939 0 + 934 171 943 945 0 + 945 943 321 944 0 + 939 945 944 324 0 + 324 944 949 948 0 + 944 321 946 949 0 + 949 946 138 947 0 + 948 949 947 322 0 + 323 940 952 951 0 + 940 324 948 952 0 + 952 948 322 950 0 + 951 952 950 172 0 + 126 925 955 125 0 + 925 316 953 955 0 + 955 953 326 954 0 + 125 955 954 124 0 + 316 922 957 953 0 + 922 173 941 957 0 + 957 941 323 956 0 + 953 957 956 326 0 + 326 956 960 959 0 + 956 323 951 960 0 + 960 951 172 958 0 + 959 960 958 325 0 + 124 954 962 123 0 + 954 326 959 962 0 + 962 959 325 961 0 + 123 962 961 122 0 + 10 11 965 930 0 + 11 12 963 965 0 + 965 963 329 964 0 + 930 965 964 318 0 + 12 13 968 963 0 + 13 14 966 968 0 + 968 966 327 967 0 + 963 968 967 329 0 + 329 967 972 971 0 + 967 327 969 972 0 + 972 969 175 970 0 + 971 972 970 328 0 + 318 964 974 933 0 + 964 329 971 974 0 + 974 971 328 973 0 + 933 974 973 171 0 + 14 15 977 966 0 + 15 16 975 977 0 + 977 975 331 976 0 + 966 977 976 327 0 + 16 17 979 975 0 + 17 18 545 979 0 + 979 545 225 978 0 + 975 979 978 331 0 + 331 978 982 981 0 + 978 225 542 982 0 + 982 542 149 980 0 + 981 982 980 330 0 + 327 976 984 969 0 + 976 331 981 984 0 + 984 981 330 983 0 + 969 984 983 175 0 + 175 983 988 987 0 + 983 330 985 988 0 + 988 985 334 986 0 + 987 988 986 333 0 + 330 980 990 985 0 + 980 149 534 990 0 + 990 534 222 989 0 + 985 990 989 334 0 + 334 989 993 992 0 + 989 222 531 993 0 + 993 531 132 991 0 + 992 993 991 332 0 + 333 986 996 995 0 + 986 334 992 996 0 + 996 992 332 994 0 + 995 996 994 174 0 + 171 973 999 943 0 + 973 328 997 999 0 + 999 997 336 998 0 + 943 999 998 321 0 + 328 970 1001 997 0 + 970 175 987 1001 0 + 1001 987 333 1000 0 + 997 1001 1000 336 0 + 336 1000 1004 1003 0 + 1000 333 995 1004 0 + 1004 995 174 1002 0 + 1003 1004 1002 335 0 + 321 998 1006 946 0 + 998 336 1003 1006 0 + 1006 1003 335 1005 0 + 946 1006 1005 138 0 + 138 1005 1010 1009 0 + 1005 335 1007 1010 0 + 1010 1007 340 1008 0 + 1009 1010 1008 339 0 + 335 1002 1013 1007 0 + 1002 174 1011 1013 0 + 1013 1011 337 1012 0 + 1007 1013 1012 340 0 + 340 1012 1017 1016 0 + 1012 337 1014 1017 0 + 1017 1014 177 1015 0 + 1016 1017 1015 338 0 + 339 1008 1020 1019 0 + 1008 340 1016 1020 0 + 1020 1016 338 1018 0 + 1019 1020 1018 176 0 + 174 994 1023 1011 0 + 994 332 1021 1023 0 + 1023 1021 342 1022 0 + 1011 1023 1022 337 0 + 332 991 1025 1021 0 + 991 132 500 1025 0 + 1025 500 214 1024 0 + 1021 1025 1024 342 0 + 342 1024 1028 1027 0 + 1024 214 497 1028 0 + 1028 497 146 1026 0 + 1027 1028 1026 341 0 + 337 1022 1030 1014 0 + 1022 342 1027 1030 0 + 1030 1027 341 1029 0 + 1014 1030 1029 177 0 + 177 1029 1034 1033 0 + 1029 341 1031 1034 0 + 1034 1031 344 1032 0 + 1033 1034 1032 343 0 + 341 1026 1036 1031 0 + 1026 146 488 1036 0 + 1036 488 211 1035 0 + 1031 1036 1035 344 0 + 344 1035 1038 1037 0 + 1035 211 485 1038 0 + 1038 485 130 860 0 + 1037 1038 860 302 0 + 343 1032 1040 1039 0 + 1032 344 1037 1040 0 + 1040 1037 302 857 0 + 1039 1040 857 167 0 + 176 1018 1044 1043 0 + 1018 338 1041 1044 0 + 1044 1041 346 1042 0 + 1043 1044 1042 345 0 + 338 1015 1046 1041 0 + 1015 177 1033 1046 0 + 1046 1033 343 1045 0 + 1041 1046 1045 346 0 + 346 1045 1048 1047 0 + 1045 343 1039 1048 0 + 1048 1039 167 847 0 + 1047 1048 847 299 0 + 345 1042 1050 1049 0 + 1042 346 1047 1050 0 + 1050 1047 299 844 0 + 1049 1050 844 136 0 + 122 961 1053 121 0 + 961 325 1051 1053 0 + 1053 1051 349 1052 0 + 121 1053 1052 120 0 + 325 958 1056 1051 0 + 958 172 1054 1056 0 + 1056 1054 347 1055 0 + 1051 1056 1055 349 0 + 349 1055 1060 1059 0 + 1055 347 1057 1060 0 + 1060 1057 178 1058 0 + 1059 1060 1058 348 0 + 120 1052 1062 119 0 + 1052 349 1059 1062 0 + 1062 1059 348 1061 0 + 119 1062 1061 118 0 + 172 950 1065 1054 0 + 950 322 1063 1065 0 + 1065 1063 351 1064 0 + 1054 1065 1064 347 0 + 322 947 1067 1063 0 + 947 138 1009 1067 0 + 1067 1009 339 1066 0 + 1063 1067 1066 351 0 + 351 1066 1070 1069 0 + 1066 339 1019 1070 0 + 1070 1019 176 1068 0 + 1069 1070 1068 350 0 + 347 1064 1072 1057 0 + 1064 351 1069 1072 0 + 1072 1069 350 1071 0 + 1057 1072 1071 178 0 + 178 1071 1076 1075 0 + 1071 350 1073 1076 0 + 1076 1073 353 1074 0 + 1075 1076 1074 352 0 + 350 1068 1078 1073 0 + 1068 176 1043 1078 0 + 1078 1043 345 1077 0 + 1073 1078 1077 353 0 + 353 1077 1080 1079 0 + 1077 345 1049 1080 0 + 1080 1049 136 810 0 + 1079 1080 810 289 0 + 352 1074 1082 1081 0 + 1074 353 1079 1082 0 + 1082 1079 289 807 0 + 1081 1082 807 164 0 + 118 1061 1085 117 0 + 1061 348 1083 1085 0 + 1085 1083 354 1084 0 + 117 1085 1084 116 0 + 348 1058 1087 1083 0 + 1058 178 1075 1087 0 + 1087 1075 352 1086 0 + 1083 1087 1086 354 0 + 354 1086 1089 1088 0 + 1086 352 1081 1089 0 + 1089 1081 164 797 0 + 1088 1089 797 286 0 + 116 1084 1090 115 0 + 1084 354 1088 1090 0 + 1090 1088 286 794 0 + 115 1090 794 114 0 + End diff --git a/examples/forward_problems_2d/complex_mesh/poisson_2d/input.yaml b/examples/forward_problems_2d/complex_mesh/poisson_2d/input.yaml new file mode 100644 index 0000000..75613ac --- /dev/null +++ b/examples/forward_problems_2d/complex_mesh/poisson_2d/input.yaml @@ -0,0 +1,75 @@ +# This YAML file contains configuration parameters for a variational physics-informed neural network (VarPINN) experimentation. + +experimentation: + output_path: "output/poisson2d/1" # Path to the output directory where the results will be saved. + +geometry: + mesh_generation_method: "external" # Method for generating the mesh. Can be "internal" or "external". + generate_mesh_plot: True # Flag indicating whether to generate a plot of the mesh. + + # internal mesh generated quadrilateral mesh, depending on the parameters specified below. + + internal_mesh_params: # Parameters for internal mesh generation method. + x_min: 0 # Minimum x-coordinate of the domain. + x_max: 1 # Maximum x-coordinate of the domain. + y_min: 0 # Minimum y-coordinate of the domain. + y_max: 1 # Maximum y-coordinate of the domain. + n_cells_x: 4 # Number of cells in the x-direction. + n_cells_y: 4 # Number of cells in the y-direction. + n_boundary_points: 400 # Number of boundary points. + n_test_points_x: 100 # Number of test points in the x-direction. + n_test_points_y: 100 # Number of test points in the y-direction. + + exact_solution: + exact_solution_generation: "external" # whether the exact solution needs to be read from external file. + exact_solution_file_name: "" # External solution file name. + + mesh_type: "quadrilateral" # Type of mesh. Can be "quadrilateral" or other supported types. + + external_mesh_params: # Parameters for external mesh generation method. + mesh_file_name: "../meshes/circle_quad.mesh" # Path to the external mesh file (should be a .mesh file). + boundary_refinement_level: 4 # Level of refinement for the boundary. + boundary_sampling_method: "lhs" # Method for sampling the boundary. Can be "uniform" or "lhs". + +fe: + fe_order: 2 # Order of the finite element basis functions. + fe_type: "legendre" # Type of finite element basis functions. Can be "jacobi" or other supported types. + quad_order: 3 # Order of the quadrature rule. + quad_type: "gauss-jacobi" # Type of quadrature rule. Can be "gauss-jacobi" or other supported types. + +pde: + beta: 10 # Parameter for the PDE. + +model: + model_architecture: [2, 50,50,50,50, 1] # Architecture of the neural network model. + activation: "tanh" # Activation function used in the neural network. + use_attention: False # Flag indicating whether to use attention mechanism in the model. + epochs: 10000 # Number of training epochs. + dtype: "float32" # Data type used for computations. + set_memory_growth: False # Flag indicating whether to set memory growth for GPU. + + learning_rate: # Parameters for learning rate scheduling. + initial_learning_rate: 0.001 # Initial learning rate. + use_lr_scheduler: False # Flag indicating whether to use learning rate scheduler. + decay_steps: 1000 # Number of steps between each learning rate decay. + decay_rate: 0.99 # Decay rate for the learning rate. + staircase: False # Flag indicating whether to use staircase decay. + + +logging: + update_progress_bar: 100 # Number of steps between each update of the progress bar. + update_console_output: 5000 # Number of steps between each update of the console output. + update_solution_images: 10000 # Number of steps between each update of the intermediate solution images. + plot_residual_images: True + test_error_last_n_epochs: 1000 + +wandb: + use_wandb: False # Flag indicating whether to use Weights & Biases for logging. + project_name: "Volker_example_2" # Name of the Weights & Biases project. + wandb_run_prefix: "without_scaling" # Prefix for the Weights & Biases run. + entity: "starslab-iisc" # Weights & Biases entity. + +additional: + run_by: "Thivin" # Name of the person running the experiment. + System: "24" # System identifier. + diff --git a/examples/forward_problems_2d/complex_mesh/poisson_2d/main_poisson2d.py b/examples/forward_problems_2d/complex_mesh/poisson_2d/main_poisson2d.py new file mode 100644 index 0000000..4d91a0b --- /dev/null +++ b/examples/forward_problems_2d/complex_mesh/poisson_2d/main_poisson2d.py @@ -0,0 +1,309 @@ +import numpy as np +import pandas as pd +import pytest +import tensorflow as tf +from pathlib import Path +from tqdm import tqdm +import yaml +import sys +import copy +from tensorflow.keras import layers +from tensorflow.keras import initializers +from rich.console import Console +import copy +import time + + +from fastvpinns.Geometry.geometry_2d import Geometry_2D +from fastvpinns.FE_2D.fespace2d import Fespace2D +from fastvpinns.data.datahandler2d import DataHandler2D +from fastvpinns.model.model import DenseModel +from fastvpinns.physics.poisson2d import pde_loss_poisson +from fastvpinns.utils.plot_utils import plot_contour, plot_loss_function, plot_test_loss_function +from fastvpinns.utils.compute_utils import compute_errors_combined +from fastvpinns.utils.print_utils import print_table + +# import the example file +from sin_cos import * + +# import all files from utility +from utility import * + +if __name__ == "__main__": + + console = Console() + + # check input arguments + if len(sys.argv) != 2: + print("Usage: python main.py ") + sys.exit(1) + + # Read the YAML file + with open(sys.argv[1], 'r') as f: + config = yaml.safe_load(f) + + # Extract the values from the YAML file + i_output_path = config['experimentation']['output_path'] + + i_mesh_generation_method = config['geometry']['mesh_generation_method'] + i_generate_mesh_plot = config['geometry']['generate_mesh_plot'] + i_mesh_type = config['geometry']['mesh_type'] + i_x_min = config['geometry']['internal_mesh_params']['x_min'] + i_x_max = config['geometry']['internal_mesh_params']['x_max'] + i_y_min = config['geometry']['internal_mesh_params']['y_min'] + i_y_max = config['geometry']['internal_mesh_params']['y_max'] + i_n_cells_x = config['geometry']['internal_mesh_params']['n_cells_x'] + i_n_cells_y = config['geometry']['internal_mesh_params']['n_cells_y'] + i_n_boundary_points = config['geometry']['internal_mesh_params']['n_boundary_points'] + i_n_test_points_x = config['geometry']['internal_mesh_params']['n_test_points_x'] + i_n_test_points_y = config['geometry']['internal_mesh_params']['n_test_points_y'] + i_exact_solution_generation = config['geometry']['exact_solution']['exact_solution_generation'] + i_exact_solution_file_name = config['geometry']['exact_solution']['exact_solution_file_name'] + + i_mesh_file_name = config['geometry']['external_mesh_params']['mesh_file_name'] + i_boundary_refinement_level = config['geometry']['external_mesh_params'][ + 'boundary_refinement_level' + ] + i_boundary_sampling_method = config['geometry']['external_mesh_params'][ + 'boundary_sampling_method' + ] + + i_fe_order = config['fe']['fe_order'] + i_fe_type = config['fe']['fe_type'] + i_quad_order = config['fe']['quad_order'] + i_quad_type = config['fe']['quad_type'] + + i_model_architecture = config['model']['model_architecture'] + i_activation = config['model']['activation'] + i_use_attention = config['model']['use_attention'] + i_epochs = config['model']['epochs'] + i_dtype = config['model']['dtype'] + if i_dtype == "float64": + i_dtype = tf.float64 + elif i_dtype == "float32": + i_dtype = tf.float32 + else: + print("[ERROR] The given dtype is not a valid tensorflow dtype") + raise ValueError("The given dtype is not a valid tensorflow dtype") + + i_set_memory_growth = config['model']['set_memory_growth'] + i_learning_rate_dict = config['model']['learning_rate'] + + i_beta = config['pde']['beta'] + + i_update_progress_bar = config['logging']['update_progress_bar'] + i_update_console_output = config['logging']['update_console_output'] + i_update_solution_images = config['logging']['update_solution_images'] + + # use pathlib to create the folder,if it does not exist + folder = Path(i_output_path) + # create the folder if it does not exist + if not folder.exists(): + folder.mkdir(parents=True, exist_ok=True) + + # get the boundary function dictionary from example file + bound_function_dict, bound_condition_dict = get_boundary_function_dict(), get_bound_cond_dict() + + # Initiate a Geometry_2D object + domain = Geometry_2D( + i_mesh_type, i_mesh_generation_method, i_n_test_points_x, i_n_test_points_y, i_output_path + ) + + # load the mesh + # cells, boundary_points = domain.generate_quad_mesh_internal(x_limits = [i_x_min, i_x_max], \ + # y_limits = [i_y_min, i_y_max], \ + # n_cells_x = i_n_cells_x, \ + # n_cells_y = i_n_cells_y, \ + # num_boundary_points=i_n_boundary_points) + + cells, boundary_points = domain.read_mesh( + i_mesh_file_name, + i_boundary_refinement_level, + i_boundary_sampling_method, + refinement_level=1, + ) + + # get the boundary function dictionary from example file + bound_function_dict, bound_condition_dict = get_boundary_function_dict(), get_bound_cond_dict() + + fespace = Fespace2D( + mesh=domain.mesh, + cells=cells, + boundary_points=boundary_points, + cell_type=domain.mesh_type, + fe_order=i_fe_order, + fe_type=i_fe_type, + quad_order=i_quad_order, + quad_type=i_quad_type, + fe_transformation_type="bilinear", + bound_function_dict=bound_function_dict, + bound_condition_dict=bound_condition_dict, + forcing_function=rhs, + output_path=i_output_path, + generate_mesh_plot=i_generate_mesh_plot, + ) + + # instantiate data handler + datahandler = DataHandler2D(fespace, domain, dtype=i_dtype) + + params_dict = {} + params_dict['n_cells'] = fespace.n_cells + + # get the input data for the PDE + train_dirichlet_input, train_dirichlet_output = datahandler.get_dirichlet_input() + + # get bilinear parameters + # this function will obtain the values of the bilinear parameters from the model + # and convert them into tensors of desired dtype + bilinear_params_dict = datahandler.get_bilinear_params_dict_as_tensors(get_bilinear_params_dict) + + model = DenseModel( + layer_dims=[2, 30, 30, 30, 1], + learning_rate_dict=i_learning_rate_dict, + params_dict=params_dict, + loss_function=pde_loss_poisson, + input_tensors_list=[datahandler.x_pde_list, train_dirichlet_input, train_dirichlet_output], + orig_factor_matrices=[ + datahandler.shape_val_mat_list, + datahandler.grad_x_mat_list, + datahandler.grad_y_mat_list, + ], + force_function_list=datahandler.forcing_function_list, + tensor_dtype=i_dtype, + use_attention=i_use_attention, + activation=i_activation, + hessian=False, + ) + + test_points = domain.get_test_points() + print(f"[bold]Number of Test Points = [/bold] {test_points.shape[0]}") + y_exact = exact_solution(test_points[:, 0], test_points[:, 1]) + + # plot the exact solution + num_epochs = i_epochs # num_epochs + progress_bar = tqdm( + total=num_epochs, + desc='Training', + unit='epoch', + bar_format="{l_bar}{bar:40}{r_bar}{bar:-10b}", + colour="green", + ncols=100, + ) + loss_array = [] # total loss + test_loss_array = [] # test loss + time_array = [] # time per epoc + # beta - boundary loss parameters + beta = tf.constant(i_beta, dtype=i_dtype) + + # ---------------------------------------------------------------# + # ------------- TRAINING LOOP ---------------------------------- # + # ---------------------------------------------------------------# + for epoch in range(num_epochs): + + # Train the model + batch_start_time = time.time() + loss = model.train_step(beta=beta, bilinear_params_dict=bilinear_params_dict) + elapsed = time.time() - batch_start_time + + # print(elapsed) + time_array.append(elapsed) + + loss_array.append(loss['loss']) + + # ------ Intermediate results update ------ # + if (epoch + 1) % i_update_console_output == 0 or epoch == num_epochs - 1: + y_pred = model(test_points).numpy() + y_pred = y_pred.reshape(-1) + + error = np.abs(y_exact - y_pred) + + # get errors + ( + l2_error, + linf_error, + l2_error_relative, + linf_error_relative, + l1_error, + l1_error_relative, + ) = compute_errors_combined(y_exact, y_pred) + + loss_pde = float(loss['loss_pde'].numpy()) + loss_dirichlet = float(loss['loss_dirichlet'].numpy()) + total_loss = float(loss['loss'].numpy()) + + # Append test loss + test_loss_array.append(l1_error) + + solution_array = np.c_[y_pred, y_exact, np.abs(y_exact - y_pred)] + domain.write_vtk( + solution_array, + output_path=i_output_path, + filename=f"prediction_{epoch+1}.vtk", + data_names=["Sol", "Exact", "Error"], + ) + + console.print(f"\nEpoch [bold]{epoch+1}/{num_epochs}[/bold]") + console.print("[bold]--------------------[/bold]") + console.print("[bold]Beta : [/bold]", beta.numpy(), end=" ") + console.print( + f"Variational Losses || Pde Loss : [red]{loss_pde:.3e}[/red] Dirichlet Loss : [red]{loss_dirichlet:.3e}[/red] Total Loss : [red]{total_loss:.3e}[/red]" + ) + console.print( + f"Test Losses || L1 Error : {l1_error:.3e} L2 Error : {l2_error:.3e} Linf Error : {linf_error:.3e}" + ) + + progress_bar.update(1) + + # Save the model + model.save_weights(str(Path(i_output_path) / "model_weights")) + + solution_array = np.c_[y_pred, y_exact, np.abs(y_exact - y_pred)] + domain.write_vtk( + solution_array, + output_path=i_output_path, + filename=f"prediction_{epoch+1}.vtk", + data_names=["Sol", "Exact", "Error"], + ) + # print the Error values in table + print_table( + "Error Values", + ["Error Type", "Value"], + [ + "L2 Error", + "Linf Error", + "Relative L2 Error", + "Relative Linf Error", + "L1 Error", + "Relative L1 Error", + ], + [l2_error, linf_error, l2_error_relative, linf_error_relative, l1_error, l1_error_relative], + ) + + # print the time values in table + print_table( + "Time Values", + ["Time Type", "Value"], + [ + "Time per Epoch(s) - Median", + "Time per Epoch(s) IQR-25% ", + "Time per Epoch(s) IQR-75% ", + "Mean (s)", + "Epochs per second", + "Total Train Time", + ], + [ + np.median(time_array), + np.percentile(time_array, 25), + np.percentile(time_array, 75), + np.mean(time_array), + int(i_epochs / np.sum(time_array)), + np.sum(time_array), + ], + ) + + # save all the arrays as numpy arrays + np.savetxt(str(Path(i_output_path) / "loss_function.txt"), np.array(loss_array)) + np.savetxt(str(Path(i_output_path) / "prediction.txt"), y_pred) + np.savetxt(str(Path(i_output_path) / "exact.txt"), y_exact) + np.savetxt(str(Path(i_output_path) / "error.txt"), error) + np.savetxt(str(Path(i_output_path) / "time_per_epoch.txt"), np.array(time_array)) diff --git a/examples/forward_problems_2d/complex_mesh/poisson_2d/sin_cos.py b/examples/forward_problems_2d/complex_mesh/poisson_2d/sin_cos.py new file mode 100644 index 0000000..da6f50e --- /dev/null +++ b/examples/forward_problems_2d/complex_mesh/poisson_2d/sin_cos.py @@ -0,0 +1,93 @@ +# Example file for the poisson problem +# Path: examples/poisson.py +# file contains the exact solution, rhs and boundary conditions for the poisson problem +import numpy as np +import tensorflow as tf + + +def left_boundary(x, y): + """ + This function will return the boundary value for given component of a boundary + """ + omegaX = 2.0 * np.pi + omegaY = 2.0 * np.pi + return -1.0 * np.sin(omegaX * x) * np.sin(omegaY * y) + + +def right_boundary(x, y): + """ + This function will return the boundary value for given component of a boundary + """ + val = 0.0 + omegaX = 2.0 * np.pi + omegaY = 2.0 * np.pi + return -1.0 * np.sin(omegaX * x) * np.sin(omegaY * y) + + +def top_boundary(x, y): + """ + This function will return the boundary value for given component of a boundary + """ + val = 0.0 + omegaX = 2.0 * np.pi + omegaY = 2.0 * np.pi + return -1.0 * np.sin(omegaX * x) * np.sin(omegaY * y) + + +def bottom_boundary(x, y): + """ + This function will return the boundary value for given component of a boundary + """ + omegaX = 2.0 * np.pi + omegaY = 2.0 * np.pi + return -1.0 * np.sin(omegaX * x) * np.sin(omegaY * y) + + +def rhs(x, y): + """ + This function will return the value of the rhs at a given point + """ + # f_temp = 32 * (x * (1 - x) + y * (1 - y)) + # f_temp = 1 + + omegaX = 2.0 * np.pi + omegaY = 2.0 * np.pi + f_temp = -2.0 * (omegaX**2) * (np.sin(omegaX * x) * np.sin(omegaY * y)) + + return f_temp + + +def exact_solution(x, y): + """ + This function will return the exact solution at a given point + """ + + # val = 16 * x * (1 - x) * y * (1 - y) + omegaX = 2.0 * np.pi + omegaY = 2.0 * np.pi + val = -1.0 * np.sin(omegaX * x) * np.sin(omegaY * y) + + return val + + +def get_boundary_function_dict(): + """ + This function will return a dictionary of boundary functions + """ + return {1000: bottom_boundary, 1001: right_boundary, 1002: top_boundary, 1003: left_boundary} + + +def get_bound_cond_dict(): + """ + This function will return a dictionary of boundary conditions + """ + return {1000: "dirichlet", 1001: "dirichlet", 1002: "dirichlet", 1003: "dirichlet"} + + +def get_bilinear_params_dict(): + """ + This function will return a dictionary of bilinear parameters + """ + eps = 1.0 + + return {"eps": eps} diff --git a/examples/forward_problems_2d/complex_mesh/poisson_2d/utility.py b/examples/forward_problems_2d/complex_mesh/poisson_2d/utility.py new file mode 100644 index 0000000..794a0ea --- /dev/null +++ b/examples/forward_problems_2d/complex_mesh/poisson_2d/utility.py @@ -0,0 +1,113 @@ +import sys +import yaml +import numpy as np + +from fastvpinns.utils.plot_utils import plot_contour, plot_loss_function, plot_test_loss_function +from fastvpinns.utils.compute_utils import compute_errors_combined + + +def get_errors( + model, + console, + y_pred, + y_exact, + Y_Exact_Matrix, + i_n_test_points_x, + i_n_test_points_y, + i_output_path, + epoch, + loss, + num_epochs, +): + """ + Calculate and return various error metrics and loss values. + + Args: + model (object): The trained model. + console (object): The console object for printing messages. + y_exact (array): The exact solution. + Y_Exact_Matrix (array): The matrix of exact solutions. + i_n_test_points_x (int): The number of test points in the x-direction. + i_n_test_points_y (int): The number of test points in the y-direction. + i_output_path (str): The output path for saving plots. + epoch (int): The current epoch number. + loss (dict): The dictionary containing different loss values. + num_epochs (int): The total number of epochs. + + Returns: + dict: A dictionary containing various error metrics and loss values. + """ + + # Compute error metrics + l2_error, linf_error, l2_error_relative, linf_error_relative, l1_error, l1_error_relative = ( + compute_errors_combined(y_exact, y_pred) + ) + + # Print epoch information + console.print(f"\nEpoch [bold]{epoch+1}/{num_epochs}[/bold]") + console.print("[bold]--------------------[/bold]") + console.print( + f"Variational Losses || Pde Loss : [red]{loss_pde:.3e}[/red] Dirichlet Loss : [red]{loss_dirichlet:.3e}[/red] Total Loss : [red]{total_loss:.3e}[/red]" + ) + console.print(f"Test Losses || L1 Error : {l1_error:.3e}", end=" ") + console.print(f"L2 Error : {l2_error:.3e}", end=" ") + console.print(f"Linf Error : {linf_error:.3e}", end="\n") + + return { + 'l2_error': l2_error, + 'linf_error': linf_error, + 'l2_error_relative': l2_error_relative, + 'linf_error_relative': linf_error_relative, + 'l1_error': l1_error, + 'l1_error_relative': l1_error_relative, + 'loss_pde': loss_pde, + 'loss_dirichlet': loss_dirichlet, + 'total_loss': total_loss, + } + + +def plot_results( + loss_array, + test_loss_array, + y_pred, + X, + Y, + Y_Exact_Matrix, + i_output_path, + epoch, + i_n_test_points_x, + i_n_test_points_y, +): + """ + Plot the loss function, test loss function, solution, and error. + + Args: + loss_array (array): Array of loss values during training. + test_loss_array (array): Array of test loss values during training. + y_pred (array): Predicted solution. + X (array): X-coordinates of the grid. + Y (array): Y-coordinates of the grid. + Y_Exact_Matrix (array): Matrix of exact solutions. + i_output_path (str): Output path for saving plots. + epoch (int): Current epoch number. + i_n_test_points_x (int): Number of test points in the x-direction. + i_n_test_points_y (int): Number of test points in the y-direction. + """ + # plot loss + plot_loss_function(loss_array, i_output_path) # plots NN loss + plot_test_loss_function(test_loss_array, i_output_path) # plots test loss + + # plot solution + y_pred = y_pred.reshape(i_n_test_points_x, i_n_test_points_y) + error = np.abs(Y_Exact_Matrix - y_pred) + plot_contour( + x=X, + y=Y, + z=y_pred, + output_path=i_output_path, + filename=f"prediction_{epoch+1}", + title="Prediction", + ) + plot_contour( + x=X, y=Y, z=error, output_path=i_output_path, filename=f"error_{epoch+1}", title="Error" + ) diff --git a/examples/forward_problems_2d/uniform_mesh/helmholtz_2d/helmholtz_example.py b/examples/forward_problems_2d/uniform_mesh/helmholtz_2d/helmholtz_example.py new file mode 100644 index 0000000..0899265 --- /dev/null +++ b/examples/forward_problems_2d/uniform_mesh/helmholtz_2d/helmholtz_example.py @@ -0,0 +1,83 @@ +# Example file for the poisson problem +# Path: examples/poisson.py +# file contains the exact solution, rhs and boundary conditions for the poisson problem +import numpy as np +import tensorflow as tf + + +def left_boundary(x, y): + """ + This function will return the boundary value for given component of a boundary + """ + return (x + y) * np.sin(np.pi * x) * np.sin(np.pi * y) + + +def right_boundary(x, y): + """ + This function will return the boundary value for given component of a boundary + """ + val = 0.0 + return (x + y) * np.sin(np.pi * x) * np.sin(np.pi * y) + + +def top_boundary(x, y): + """ + This function will return the boundary value for given component of a boundary + """ + val = 0.0 + return (x + y) * np.sin(np.pi * x) * np.sin(np.pi * y) + + +def bottom_boundary(x, y): + """ + This function will return the boundary value for given component of a boundary + """ + return (x + y) * np.sin(np.pi * x) * np.sin(np.pi * y) + + +def rhs(x, y): + """ + This function will return the value of the rhs at a given point + """ + # f_temp = 32 * (x * (1 - x) + y * (1 - y)) + # f_temp = 1 + + term1 = 2 * np.pi * np.cos(np.pi * y) * np.sin(np.pi * x) + term2 = 2 * np.pi * np.cos(np.pi * x) * np.sin(np.pi * y) + term3 = (x + y) * np.sin(np.pi * x) * np.sin(np.pi * y) + term4 = -2 * (np.pi**2) * (x + y) * np.sin(np.pi * x) * np.sin(np.pi * y) + + result = term1 + term2 + term3 + term4 + return result + + +def exact_solution(x, y): + """ + This function will return the exact solution at a given point + """ + + return (x + y) * np.sin(np.pi * x) * np.sin(np.pi * y) + + +def get_boundary_function_dict(): + """ + This function will return a dictionary of boundary functions + """ + return {1000: bottom_boundary, 1001: right_boundary, 1002: top_boundary, 1003: left_boundary} + + +def get_bound_cond_dict(): + """ + This function will return a dictionary of boundary conditions + """ + return {1000: "dirichlet", 1001: "dirichlet", 1002: "dirichlet", 1003: "dirichlet"} + + +def get_bilinear_params_dict(): + """ + This function will return a dictionary of bilinear parameters + """ + k = 1.0 + eps = 1.0 + + return {"k": k, "eps": eps} diff --git a/examples/forward_problems_2d/uniform_mesh/helmholtz_2d/input.yaml b/examples/forward_problems_2d/uniform_mesh/helmholtz_2d/input.yaml new file mode 100644 index 0000000..4c6d166 --- /dev/null +++ b/examples/forward_problems_2d/uniform_mesh/helmholtz_2d/input.yaml @@ -0,0 +1,75 @@ +# This YAML file contains configuration parameters for a variational physics-informed neural network (VarPINN) experimentation. + +experimentation: + output_path: "output/helmholtz/1" # Path to the output directory where the results will be saved. + +geometry: + mesh_generation_method: "internal" # Method for generating the mesh. Can be "internal" or "external". + generate_mesh_plot: True # Flag indicating whether to generate a plot of the mesh. + + # internal mesh generated quadrilateral mesh, depending on the parameters specified below. + + internal_mesh_params: # Parameters for internal mesh generation method. + x_min: 0 # Minimum x-coordinate of the domain. + x_max: 1 # Maximum x-coordinate of the domain. + y_min: 0 # Minimum y-coordinate of the domain. + y_max: 1 # Maximum y-coordinate of the domain. + n_cells_x: 4 # Number of cells in the x-direction. + n_cells_y: 4 # Number of cells in the y-direction. + n_boundary_points: 400 # Number of boundary points. + n_test_points_x: 100 # Number of test points in the x-direction. + n_test_points_y: 100 # Number of test points in the y-direction. + + exact_solution: + exact_solution_generation: "internal" # whether the exact solution needs to be read from external file. + exact_solution_file_name: "fem_solutions/neumann_solutions/solution_problem_3.txt" # External solution file name. + + mesh_type: "quadrilateral" # Type of mesh. Can be "quadrilateral" or other supported types. + + external_mesh_params: # Parameters for external mesh generation method. + mesh_file_name: "meshes/hemker.mesh" # Path to the external mesh file (should be a .mesh file). + boundary_refinement_level: 4 # Level of refinement for the boundary. + boundary_sampling_method: "lhs" # Method for sampling the boundary. Can be "uniform" or "lhs". + +fe: + fe_order: 6 # Order of the finite element basis functions. + fe_type: "legendre" # Type of finite element basis functions. Can be "jacobi" or other supported types. + quad_order: 10 # Order of the quadrature rule. + quad_type: "gauss-jacobi" # Type of quadrature rule. Can be "gauss-jacobi" or other supported types. + +pde: + beta: 10 # Parameter for the PDE. + +model: + model_architecture: [2, 50,50,50,50, 1] # Architecture of the neural network model. + activation: "tanh" # Activation function used in the neural network. + use_attention: False # Flag indicating whether to use attention mechanism in the model. + epochs: 10000 # Number of training epochs. + dtype: "float32" # Data type used for computations. + set_memory_growth: False # Flag indicating whether to set memory growth for GPU. + + learning_rate: # Parameters for learning rate scheduling. + initial_learning_rate: 0.001 # Initial learning rate. + use_lr_scheduler: False # Flag indicating whether to use learning rate scheduler. + decay_steps: 1000 # Number of steps between each learning rate decay. + decay_rate: 0.99 # Decay rate for the learning rate. + staircase: False # Flag indicating whether to use staircase decay. + + +logging: + update_progress_bar: 100 # Number of steps between each update of the progress bar. + update_console_output: 5000 # Number of steps between each update of the console output. + update_solution_images: 10000 # Number of steps between each update of the intermediate solution images. + plot_residual_images: True + test_error_last_n_epochs: 1000 + +wandb: + use_wandb: False # Flag indicating whether to use Weights & Biases for logging. + project_name: "Volker_example_2" # Name of the Weights & Biases project. + wandb_run_prefix: "without_scaling" # Prefix for the Weights & Biases run. + entity: "starslab-iisc" # Weights & Biases entity. + +additional: + run_by: "Thivin" # Name of the person running the experiment. + System: "24" # System identifier. + diff --git a/examples/forward_problems_2d/uniform_mesh/helmholtz_2d/main_helmholtz.py b/examples/forward_problems_2d/uniform_mesh/helmholtz_2d/main_helmholtz.py new file mode 100644 index 0000000..036ccb7 --- /dev/null +++ b/examples/forward_problems_2d/uniform_mesh/helmholtz_2d/main_helmholtz.py @@ -0,0 +1,316 @@ +import numpy as np +import pandas as pd +import pytest +import tensorflow as tf +from pathlib import Path +from tqdm import tqdm +import yaml +import sys +import copy +from tensorflow.keras import layers +from tensorflow.keras import initializers +from rich.console import Console +import copy +import time + + +from fastvpinns.Geometry.geometry_2d import Geometry_2D +from fastvpinns.FE_2D.fespace2d import Fespace2D +from fastvpinns.data.datahandler2d import DataHandler2D +from fastvpinns.model.model import DenseModel +from fastvpinns.physics.helmholtz2d import pde_loss_helmholtz +from fastvpinns.utils.plot_utils import plot_contour, plot_loss_function, plot_test_loss_function +from fastvpinns.utils.compute_utils import compute_errors_combined +from fastvpinns.utils.print_utils import print_table + +# import the example file +from helmholtz_example import * + +# import all files from utility +from utility import * + +if __name__ == "__main__": + + console = Console() + + # check input arguments + if len(sys.argv) != 2: + print("Usage: python main.py ") + sys.exit(1) + + # Read the YAML file + with open(sys.argv[1], 'r') as f: + config = yaml.safe_load(f) + + # Extract the values from the YAML file + i_output_path = config['experimentation']['output_path'] + + i_mesh_generation_method = config['geometry']['mesh_generation_method'] + i_generate_mesh_plot = config['geometry']['generate_mesh_plot'] + i_mesh_type = config['geometry']['mesh_type'] + i_x_min = config['geometry']['internal_mesh_params']['x_min'] + i_x_max = config['geometry']['internal_mesh_params']['x_max'] + i_y_min = config['geometry']['internal_mesh_params']['y_min'] + i_y_max = config['geometry']['internal_mesh_params']['y_max'] + i_n_cells_x = config['geometry']['internal_mesh_params']['n_cells_x'] + i_n_cells_y = config['geometry']['internal_mesh_params']['n_cells_y'] + i_n_boundary_points = config['geometry']['internal_mesh_params']['n_boundary_points'] + i_n_test_points_x = config['geometry']['internal_mesh_params']['n_test_points_x'] + i_n_test_points_y = config['geometry']['internal_mesh_params']['n_test_points_y'] + i_exact_solution_generation = config['geometry']['exact_solution']['exact_solution_generation'] + i_exact_solution_file_name = config['geometry']['exact_solution']['exact_solution_file_name'] + + i_mesh_file_name = config['geometry']['external_mesh_params']['mesh_file_name'] + i_boundary_refinement_level = config['geometry']['external_mesh_params'][ + 'boundary_refinement_level' + ] + i_boundary_sampling_method = config['geometry']['external_mesh_params'][ + 'boundary_sampling_method' + ] + + i_fe_order = config['fe']['fe_order'] + i_fe_type = config['fe']['fe_type'] + i_quad_order = config['fe']['quad_order'] + i_quad_type = config['fe']['quad_type'] + + i_model_architecture = config['model']['model_architecture'] + i_activation = config['model']['activation'] + i_use_attention = config['model']['use_attention'] + i_epochs = config['model']['epochs'] + i_dtype = config['model']['dtype'] + if i_dtype == "float64": + i_dtype = tf.float64 + elif i_dtype == "float32": + i_dtype = tf.float32 + else: + print("[ERROR] The given dtype is not a valid tensorflow dtype") + raise ValueError("The given dtype is not a valid tensorflow dtype") + + i_set_memory_growth = config['model']['set_memory_growth'] + i_learning_rate_dict = config['model']['learning_rate'] + + i_beta = config['pde']['beta'] + + i_update_progress_bar = config['logging']['update_progress_bar'] + i_update_console_output = config['logging']['update_console_output'] + i_update_solution_images = config['logging']['update_solution_images'] + + # use pathlib to create the folder,if it does not exist + folder = Path(i_output_path) + # create the folder if it does not exist + if not folder.exists(): + folder.mkdir(parents=True, exist_ok=True) + + # get the boundary function dictionary from example file + bound_function_dict, bound_condition_dict = get_boundary_function_dict(), get_bound_cond_dict() + + # Initiate a Geometry_2D object + domain = Geometry_2D( + i_mesh_type, i_mesh_generation_method, i_n_test_points_x, i_n_test_points_y, i_output_path + ) + + # load the mesh + cells, boundary_points = domain.generate_quad_mesh_internal( + x_limits=[i_x_min, i_x_max], + y_limits=[i_y_min, i_y_max], + n_cells_x=i_n_cells_x, + n_cells_y=i_n_cells_y, + num_boundary_points=i_n_boundary_points, + ) + + # get the boundary function dictionary from example file + bound_function_dict, bound_condition_dict = get_boundary_function_dict(), get_bound_cond_dict() + + fespace = Fespace2D( + mesh=domain.mesh, + cells=cells, + boundary_points=boundary_points, + cell_type=domain.mesh_type, + fe_order=i_fe_order, + fe_type=i_fe_type, + quad_order=i_quad_order, + quad_type=i_quad_type, + fe_transformation_type="bilinear", + bound_function_dict=bound_function_dict, + bound_condition_dict=bound_condition_dict, + forcing_function=rhs, + output_path=i_output_path, + generate_mesh_plot=i_generate_mesh_plot, + ) + + # instantiate data handler + datahandler = DataHandler2D(fespace, domain, dtype=i_dtype) + + params_dict = {} + params_dict['n_cells'] = fespace.n_cells + + # get the input data for the PDE + train_dirichlet_input, train_dirichlet_output = datahandler.get_dirichlet_input() + + # get bilinear parameters + # this function will obtain the values of the bilinear parameters from the model + # and convert them into tensors of desired dtype + bilinear_params_dict = datahandler.get_bilinear_params_dict_as_tensors(get_bilinear_params_dict) + + model = DenseModel( + layer_dims=[2, 30, 30, 30, 1], + learning_rate_dict=i_learning_rate_dict, + params_dict=params_dict, + loss_function=pde_loss_helmholtz, + input_tensors_list=[datahandler.x_pde_list, train_dirichlet_input, train_dirichlet_output], + orig_factor_matrices=[ + datahandler.shape_val_mat_list, + datahandler.grad_x_mat_list, + datahandler.grad_y_mat_list, + ], + force_function_list=datahandler.forcing_function_list, + tensor_dtype=i_dtype, + use_attention=i_use_attention, + activation=i_activation, + hessian=False, + ) + + test_points = domain.get_test_points() + print(f"[bold]Number of Test Points = [/bold] {test_points.shape[0]}") + y_exact = exact_solution(test_points[:, 0], test_points[:, 1]) + + # save points for plotting + X = test_points[:, 0].reshape(i_n_test_points_x, i_n_test_points_y) + Y = test_points[:, 1].reshape(i_n_test_points_x, i_n_test_points_y) + Y_Exact_Matrix = y_exact.reshape(i_n_test_points_x, i_n_test_points_y) + + # plot the exact solution + plot_contour( + x=X, + y=Y, + z=Y_Exact_Matrix, + output_path=i_output_path, + filename="exact_solution", + title="Exact Solution", + ) + + num_epochs = i_epochs # num_epochs + progress_bar = tqdm( + total=num_epochs, + desc='Training', + unit='epoch', + bar_format="{l_bar}{bar:40}{r_bar}{bar:-10b}", + colour="green", + ncols=100, + ) + loss_array = [] # total loss + test_loss_array = [] # test loss + time_array = [] # time per epoc + # beta - boundary loss parameters + beta = tf.constant(i_beta, dtype=i_dtype) + + # ---------------------------------------------------------------# + # ------------- TRAINING LOOP ---------------------------------- # + # ---------------------------------------------------------------# + for epoch in range(num_epochs): + + # Train the model + batch_start_time = time.time() + loss = model.train_step(beta=beta, bilinear_params_dict=bilinear_params_dict) + elapsed = time.time() - batch_start_time + + # print(elapsed) + time_array.append(elapsed) + + loss_array.append(loss['loss']) + + # ------ Intermediate results update ------ # + if (epoch + 1) % i_update_console_output == 0 or epoch == num_epochs - 1: + y_pred = model(test_points).numpy() + y_pred = y_pred.reshape(-1) + + error = np.abs(y_exact - y_pred) + + # get errors + ( + l2_error, + linf_error, + l2_error_relative, + linf_error_relative, + l1_error, + l1_error_relative, + ) = compute_errors_combined(y_exact, y_pred) + + loss_pde = float(loss['loss_pde'].numpy()) + loss_dirichlet = float(loss['loss_dirichlet'].numpy()) + total_loss = float(loss['loss'].numpy()) + + # Append test loss + test_loss_array.append(l1_error) + + console.print(f"\nEpoch [bold]{epoch+1}/{num_epochs}[/bold]") + console.print("[bold]--------------------[/bold]") + console.print("[bold]Beta : [/bold]", beta.numpy(), end=" ") + console.print( + f"Variational Losses || Pde Loss : [red]{loss_pde:.3e}[/red] Dirichlet Loss : [red]{loss_dirichlet:.3e}[/red] Total Loss : [red]{total_loss:.3e}[/red]" + ) + console.print( + f"Test Losses || L1 Error : {l1_error:.3e} L2 Error : {l2_error:.3e} Linf Error : {linf_error:.3e}" + ) + + plot_results( + loss_array, + test_loss_array, + y_pred, + X, + Y, + Y_Exact_Matrix, + i_output_path, + epoch, + i_n_test_points_x, + i_n_test_points_y, + ) + + progress_bar.update(1) + + # Save the model + model.save_weights(str(Path(i_output_path) / "model_weights")) + + # print the Error values in table + print_table( + "Error Values", + ["Error Type", "Value"], + [ + "L2 Error", + "Linf Error", + "Relative L2 Error", + "Relative Linf Error", + "L1 Error", + "Relative L1 Error", + ], + [l2_error, linf_error, l2_error_relative, linf_error_relative, l1_error, l1_error_relative], + ) + + # print the time values in table + print_table( + "Time Values", + ["Time Type", "Value"], + [ + "Time per Epoch(s) - Median", + "Time per Epoch(s) IQR-25% ", + "Time per Epoch(s) IQR-75% ", + "Mean (s)", + "Epochs per second", + "Total Train Time", + ], + [ + np.median(time_array), + np.percentile(time_array, 25), + np.percentile(time_array, 75), + np.mean(time_array), + int(i_epochs / np.sum(time_array)), + np.sum(time_array), + ], + ) + + # save all the arrays as numpy arrays + np.savetxt(str(Path(i_output_path) / "loss_function.txt"), np.array(loss_array)) + np.savetxt(str(Path(i_output_path) / "prediction.txt"), y_pred) + np.savetxt(str(Path(i_output_path) / "exact.txt"), y_exact) + np.savetxt(str(Path(i_output_path) / "error.txt"), error) + np.savetxt(str(Path(i_output_path) / "time_per_epoch.txt"), np.array(time_array)) diff --git a/examples/forward_problems_2d/uniform_mesh/helmholtz_2d/utility.py b/examples/forward_problems_2d/uniform_mesh/helmholtz_2d/utility.py new file mode 100644 index 0000000..794a0ea --- /dev/null +++ b/examples/forward_problems_2d/uniform_mesh/helmholtz_2d/utility.py @@ -0,0 +1,113 @@ +import sys +import yaml +import numpy as np + +from fastvpinns.utils.plot_utils import plot_contour, plot_loss_function, plot_test_loss_function +from fastvpinns.utils.compute_utils import compute_errors_combined + + +def get_errors( + model, + console, + y_pred, + y_exact, + Y_Exact_Matrix, + i_n_test_points_x, + i_n_test_points_y, + i_output_path, + epoch, + loss, + num_epochs, +): + """ + Calculate and return various error metrics and loss values. + + Args: + model (object): The trained model. + console (object): The console object for printing messages. + y_exact (array): The exact solution. + Y_Exact_Matrix (array): The matrix of exact solutions. + i_n_test_points_x (int): The number of test points in the x-direction. + i_n_test_points_y (int): The number of test points in the y-direction. + i_output_path (str): The output path for saving plots. + epoch (int): The current epoch number. + loss (dict): The dictionary containing different loss values. + num_epochs (int): The total number of epochs. + + Returns: + dict: A dictionary containing various error metrics and loss values. + """ + + # Compute error metrics + l2_error, linf_error, l2_error_relative, linf_error_relative, l1_error, l1_error_relative = ( + compute_errors_combined(y_exact, y_pred) + ) + + # Print epoch information + console.print(f"\nEpoch [bold]{epoch+1}/{num_epochs}[/bold]") + console.print("[bold]--------------------[/bold]") + console.print( + f"Variational Losses || Pde Loss : [red]{loss_pde:.3e}[/red] Dirichlet Loss : [red]{loss_dirichlet:.3e}[/red] Total Loss : [red]{total_loss:.3e}[/red]" + ) + console.print(f"Test Losses || L1 Error : {l1_error:.3e}", end=" ") + console.print(f"L2 Error : {l2_error:.3e}", end=" ") + console.print(f"Linf Error : {linf_error:.3e}", end="\n") + + return { + 'l2_error': l2_error, + 'linf_error': linf_error, + 'l2_error_relative': l2_error_relative, + 'linf_error_relative': linf_error_relative, + 'l1_error': l1_error, + 'l1_error_relative': l1_error_relative, + 'loss_pde': loss_pde, + 'loss_dirichlet': loss_dirichlet, + 'total_loss': total_loss, + } + + +def plot_results( + loss_array, + test_loss_array, + y_pred, + X, + Y, + Y_Exact_Matrix, + i_output_path, + epoch, + i_n_test_points_x, + i_n_test_points_y, +): + """ + Plot the loss function, test loss function, solution, and error. + + Args: + loss_array (array): Array of loss values during training. + test_loss_array (array): Array of test loss values during training. + y_pred (array): Predicted solution. + X (array): X-coordinates of the grid. + Y (array): Y-coordinates of the grid. + Y_Exact_Matrix (array): Matrix of exact solutions. + i_output_path (str): Output path for saving plots. + epoch (int): Current epoch number. + i_n_test_points_x (int): Number of test points in the x-direction. + i_n_test_points_y (int): Number of test points in the y-direction. + """ + # plot loss + plot_loss_function(loss_array, i_output_path) # plots NN loss + plot_test_loss_function(test_loss_array, i_output_path) # plots test loss + + # plot solution + y_pred = y_pred.reshape(i_n_test_points_x, i_n_test_points_y) + error = np.abs(Y_Exact_Matrix - y_pred) + plot_contour( + x=X, + y=Y, + z=y_pred, + output_path=i_output_path, + filename=f"prediction_{epoch+1}", + title="Prediction", + ) + plot_contour( + x=X, y=Y, z=error, output_path=i_output_path, filename=f"error_{epoch+1}", title="Error" + ) diff --git a/examples/forward_problems_2d/uniform_mesh/poisson_2d/input.yaml b/examples/forward_problems_2d/uniform_mesh/poisson_2d/input.yaml new file mode 100644 index 0000000..f97a540 --- /dev/null +++ b/examples/forward_problems_2d/uniform_mesh/poisson_2d/input.yaml @@ -0,0 +1,75 @@ +# This YAML file contains configuration parameters for a variational physics-informed neural network (VarPINN) experimentation. + +experimentation: + output_path: "output/poisson2d/1" # Path to the output directory where the results will be saved. + +geometry: + mesh_generation_method: "internal" # Method for generating the mesh. Can be "internal" or "external". + generate_mesh_plot: True # Flag indicating whether to generate a plot of the mesh. + + # internal mesh generated quadrilateral mesh, depending on the parameters specified below. + + internal_mesh_params: # Parameters for internal mesh generation method. + x_min: 0 # Minimum x-coordinate of the domain. + x_max: 1 # Maximum x-coordinate of the domain. + y_min: 0 # Minimum y-coordinate of the domain. + y_max: 1 # Maximum y-coordinate of the domain. + n_cells_x: 4 # Number of cells in the x-direction. + n_cells_y: 4 # Number of cells in the y-direction. + n_boundary_points: 400 # Number of boundary points. + n_test_points_x: 100 # Number of test points in the x-direction. + n_test_points_y: 100 # Number of test points in the y-direction. + + exact_solution: + exact_solution_generation: "internal" # whether the exact solution needs to be read from external file. + exact_solution_file_name: "fem_solutions/neumann_solutions/solution_problem_3.txt" # External solution file name. + + mesh_type: "quadrilateral" # Type of mesh. Can be "quadrilateral" or other supported types. + + external_mesh_params: # Parameters for external mesh generation method. + mesh_file_name: "meshes/hemker.mesh" # Path to the external mesh file (should be a .mesh file). + boundary_refinement_level: 4 # Level of refinement for the boundary. + boundary_sampling_method: "lhs" # Method for sampling the boundary. Can be "uniform" or "lhs". + +fe: + fe_order: 6 # Order of the finite element basis functions. + fe_type: "legendre" # Type of finite element basis functions. Can be "jacobi" or other supported types. + quad_order: 10 # Order of the quadrature rule. + quad_type: "gauss-jacobi" # Type of quadrature rule. Can be "gauss-jacobi" or other supported types. + +pde: + beta: 10 # Parameter for the PDE. + +model: + model_architecture: [2, 50,50,50,50, 1] # Architecture of the neural network model. + activation: "tanh" # Activation function used in the neural network. + use_attention: False # Flag indicating whether to use attention mechanism in the model. + epochs: 10000 # Number of training epochs. + dtype: "float32" # Data type used for computations. + set_memory_growth: False # Flag indicating whether to set memory growth for GPU. + + learning_rate: # Parameters for learning rate scheduling. + initial_learning_rate: 0.001 # Initial learning rate. + use_lr_scheduler: False # Flag indicating whether to use learning rate scheduler. + decay_steps: 1000 # Number of steps between each learning rate decay. + decay_rate: 0.99 # Decay rate for the learning rate. + staircase: False # Flag indicating whether to use staircase decay. + + +logging: + update_progress_bar: 100 # Number of steps between each update of the progress bar. + update_console_output: 5000 # Number of steps between each update of the console output. + update_solution_images: 10000 # Number of steps between each update of the intermediate solution images. + plot_residual_images: True + test_error_last_n_epochs: 1000 + +wandb: + use_wandb: False # Flag indicating whether to use Weights & Biases for logging. + project_name: "Volker_example_2" # Name of the Weights & Biases project. + wandb_run_prefix: "without_scaling" # Prefix for the Weights & Biases run. + entity: "starslab-iisc" # Weights & Biases entity. + +additional: + run_by: "Thivin" # Name of the person running the experiment. + System: "24" # System identifier. + diff --git a/examples/forward_problems_2d/uniform_mesh/poisson_2d/main_poisson2d.py b/examples/forward_problems_2d/uniform_mesh/poisson_2d/main_poisson2d.py new file mode 100644 index 0000000..0075ca3 --- /dev/null +++ b/examples/forward_problems_2d/uniform_mesh/poisson_2d/main_poisson2d.py @@ -0,0 +1,316 @@ +import numpy as np +import pandas as pd +import pytest +import tensorflow as tf +from pathlib import Path +from tqdm import tqdm +import yaml +import sys +import copy +from tensorflow.keras import layers +from tensorflow.keras import initializers +from rich.console import Console +import copy +import time + + +from fastvpinns.Geometry.geometry_2d import Geometry_2D +from fastvpinns.FE_2D.fespace2d import Fespace2D +from fastvpinns.data.datahandler2d import DataHandler2D +from fastvpinns.model.model import DenseModel +from fastvpinns.physics.poisson2d import pde_loss_poisson +from fastvpinns.utils.plot_utils import plot_contour, plot_loss_function, plot_test_loss_function +from fastvpinns.utils.compute_utils import compute_errors_combined +from fastvpinns.utils.print_utils import print_table + +# import the example file +from sin_cos import * + +# import all files from utility +from utility import * + +if __name__ == "__main__": + + console = Console() + + # check input arguments + if len(sys.argv) != 2: + print("Usage: python main.py ") + sys.exit(1) + + # Read the YAML file + with open(sys.argv[1], 'r') as f: + config = yaml.safe_load(f) + + # Extract the values from the YAML file + i_output_path = config['experimentation']['output_path'] + + i_mesh_generation_method = config['geometry']['mesh_generation_method'] + i_generate_mesh_plot = config['geometry']['generate_mesh_plot'] + i_mesh_type = config['geometry']['mesh_type'] + i_x_min = config['geometry']['internal_mesh_params']['x_min'] + i_x_max = config['geometry']['internal_mesh_params']['x_max'] + i_y_min = config['geometry']['internal_mesh_params']['y_min'] + i_y_max = config['geometry']['internal_mesh_params']['y_max'] + i_n_cells_x = config['geometry']['internal_mesh_params']['n_cells_x'] + i_n_cells_y = config['geometry']['internal_mesh_params']['n_cells_y'] + i_n_boundary_points = config['geometry']['internal_mesh_params']['n_boundary_points'] + i_n_test_points_x = config['geometry']['internal_mesh_params']['n_test_points_x'] + i_n_test_points_y = config['geometry']['internal_mesh_params']['n_test_points_y'] + i_exact_solution_generation = config['geometry']['exact_solution']['exact_solution_generation'] + i_exact_solution_file_name = config['geometry']['exact_solution']['exact_solution_file_name'] + + i_mesh_file_name = config['geometry']['external_mesh_params']['mesh_file_name'] + i_boundary_refinement_level = config['geometry']['external_mesh_params'][ + 'boundary_refinement_level' + ] + i_boundary_sampling_method = config['geometry']['external_mesh_params'][ + 'boundary_sampling_method' + ] + + i_fe_order = config['fe']['fe_order'] + i_fe_type = config['fe']['fe_type'] + i_quad_order = config['fe']['quad_order'] + i_quad_type = config['fe']['quad_type'] + + i_model_architecture = config['model']['model_architecture'] + i_activation = config['model']['activation'] + i_use_attention = config['model']['use_attention'] + i_epochs = config['model']['epochs'] + i_dtype = config['model']['dtype'] + if i_dtype == "float64": + i_dtype = tf.float64 + elif i_dtype == "float32": + i_dtype = tf.float32 + else: + print("[ERROR] The given dtype is not a valid tensorflow dtype") + raise ValueError("The given dtype is not a valid tensorflow dtype") + + i_set_memory_growth = config['model']['set_memory_growth'] + i_learning_rate_dict = config['model']['learning_rate'] + + i_beta = config['pde']['beta'] + + i_update_progress_bar = config['logging']['update_progress_bar'] + i_update_console_output = config['logging']['update_console_output'] + i_update_solution_images = config['logging']['update_solution_images'] + + # use pathlib to create the folder,if it does not exist + folder = Path(i_output_path) + # create the folder if it does not exist + if not folder.exists(): + folder.mkdir(parents=True, exist_ok=True) + + # get the boundary function dictionary from example file + bound_function_dict, bound_condition_dict = get_boundary_function_dict(), get_bound_cond_dict() + + # Initiate a Geometry_2D object + domain = Geometry_2D( + i_mesh_type, i_mesh_generation_method, i_n_test_points_x, i_n_test_points_y, i_output_path + ) + + # load the mesh + cells, boundary_points = domain.generate_quad_mesh_internal( + x_limits=[i_x_min, i_x_max], + y_limits=[i_y_min, i_y_max], + n_cells_x=i_n_cells_x, + n_cells_y=i_n_cells_y, + num_boundary_points=i_n_boundary_points, + ) + + # get the boundary function dictionary from example file + bound_function_dict, bound_condition_dict = get_boundary_function_dict(), get_bound_cond_dict() + + fespace = Fespace2D( + mesh=domain.mesh, + cells=cells, + boundary_points=boundary_points, + cell_type=domain.mesh_type, + fe_order=i_fe_order, + fe_type=i_fe_type, + quad_order=i_quad_order, + quad_type=i_quad_type, + fe_transformation_type="bilinear", + bound_function_dict=bound_function_dict, + bound_condition_dict=bound_condition_dict, + forcing_function=rhs, + output_path=i_output_path, + generate_mesh_plot=i_generate_mesh_plot, + ) + + # instantiate data handler + datahandler = DataHandler2D(fespace, domain, dtype=i_dtype) + + params_dict = {} + params_dict['n_cells'] = fespace.n_cells + + # get the input data for the PDE + train_dirichlet_input, train_dirichlet_output = datahandler.get_dirichlet_input() + + # get bilinear parameters + # this function will obtain the values of the bilinear parameters from the model + # and convert them into tensors of desired dtype + bilinear_params_dict = datahandler.get_bilinear_params_dict_as_tensors(get_bilinear_params_dict) + + model = DenseModel( + layer_dims=[2, 30, 30, 30, 1], + learning_rate_dict=i_learning_rate_dict, + params_dict=params_dict, + loss_function=pde_loss_poisson, + input_tensors_list=[datahandler.x_pde_list, train_dirichlet_input, train_dirichlet_output], + orig_factor_matrices=[ + datahandler.shape_val_mat_list, + datahandler.grad_x_mat_list, + datahandler.grad_y_mat_list, + ], + force_function_list=datahandler.forcing_function_list, + tensor_dtype=i_dtype, + use_attention=i_use_attention, + activation=i_activation, + hessian=False, + ) + + test_points = domain.get_test_points() + print(f"[bold]Number of Test Points = [/bold] {test_points.shape[0]}") + y_exact = exact_solution(test_points[:, 0], test_points[:, 1]) + + # save points for plotting + X = test_points[:, 0].reshape(i_n_test_points_x, i_n_test_points_y) + Y = test_points[:, 1].reshape(i_n_test_points_x, i_n_test_points_y) + Y_Exact_Matrix = y_exact.reshape(i_n_test_points_x, i_n_test_points_y) + + # plot the exact solution + plot_contour( + x=X, + y=Y, + z=Y_Exact_Matrix, + output_path=i_output_path, + filename="exact_solution", + title="Exact Solution", + ) + + num_epochs = i_epochs # num_epochs + progress_bar = tqdm( + total=num_epochs, + desc='Training', + unit='epoch', + bar_format="{l_bar}{bar:40}{r_bar}{bar:-10b}", + colour="green", + ncols=100, + ) + loss_array = [] # total loss + test_loss_array = [] # test loss + time_array = [] # time per epoc + # beta - boundary loss parameters + beta = tf.constant(i_beta, dtype=i_dtype) + + # ---------------------------------------------------------------# + # ------------- TRAINING LOOP ---------------------------------- # + # ---------------------------------------------------------------# + for epoch in range(num_epochs): + + # Train the model + batch_start_time = time.time() + loss = model.train_step(beta=beta, bilinear_params_dict=bilinear_params_dict) + elapsed = time.time() - batch_start_time + + # print(elapsed) + time_array.append(elapsed) + + loss_array.append(loss['loss']) + + # ------ Intermediate results update ------ # + if (epoch + 1) % i_update_console_output == 0 or epoch == num_epochs - 1: + y_pred = model(test_points).numpy() + y_pred = y_pred.reshape(-1) + + error = np.abs(y_exact - y_pred) + + # get errors + ( + l2_error, + linf_error, + l2_error_relative, + linf_error_relative, + l1_error, + l1_error_relative, + ) = compute_errors_combined(y_exact, y_pred) + + loss_pde = float(loss['loss_pde'].numpy()) + loss_dirichlet = float(loss['loss_dirichlet'].numpy()) + total_loss = float(loss['loss'].numpy()) + + # Append test loss + test_loss_array.append(l1_error) + + console.print(f"\nEpoch [bold]{epoch+1}/{num_epochs}[/bold]") + console.print("[bold]--------------------[/bold]") + console.print("[bold]Beta : [/bold]", beta.numpy(), end=" ") + console.print( + f"Variational Losses || Pde Loss : [red]{loss_pde:.3e}[/red] Dirichlet Loss : [red]{loss_dirichlet:.3e}[/red] Total Loss : [red]{total_loss:.3e}[/red]" + ) + console.print( + f"Test Losses || L1 Error : {l1_error:.3e} L2 Error : {l2_error:.3e} Linf Error : {linf_error:.3e}" + ) + + plot_results( + loss_array, + test_loss_array, + y_pred, + X, + Y, + Y_Exact_Matrix, + i_output_path, + epoch, + i_n_test_points_x, + i_n_test_points_y, + ) + + progress_bar.update(1) + + # Save the model + model.save_weights(str(Path(i_output_path) / "model_weights")) + + # print the Error values in table + print_table( + "Error Values", + ["Error Type", "Value"], + [ + "L2 Error", + "Linf Error", + "Relative L2 Error", + "Relative Linf Error", + "L1 Error", + "Relative L1 Error", + ], + [l2_error, linf_error, l2_error_relative, linf_error_relative, l1_error, l1_error_relative], + ) + + # print the time values in table + print_table( + "Time Values", + ["Time Type", "Value"], + [ + "Time per Epoch(s) - Median", + "Time per Epoch(s) IQR-25% ", + "Time per Epoch(s) IQR-75% ", + "Mean (s)", + "Epochs per second", + "Total Train Time", + ], + [ + np.median(time_array), + np.percentile(time_array, 25), + np.percentile(time_array, 75), + np.mean(time_array), + int(i_epochs / np.sum(time_array)), + np.sum(time_array), + ], + ) + + # save all the arrays as numpy arrays + np.savetxt(str(Path(i_output_path) / "loss_function.txt"), np.array(loss_array)) + np.savetxt(str(Path(i_output_path) / "prediction.txt"), y_pred) + np.savetxt(str(Path(i_output_path) / "exact.txt"), y_exact) + np.savetxt(str(Path(i_output_path) / "error.txt"), error) + np.savetxt(str(Path(i_output_path) / "time_per_epoch.txt"), np.array(time_array)) diff --git a/examples/forward_problems_2d/uniform_mesh/poisson_2d/sin_cos.py b/examples/forward_problems_2d/uniform_mesh/poisson_2d/sin_cos.py new file mode 100644 index 0000000..76f34c9 --- /dev/null +++ b/examples/forward_problems_2d/uniform_mesh/poisson_2d/sin_cos.py @@ -0,0 +1,85 @@ +# Example file for the poisson problem +# Path: examples/poisson.py +# file contains the exact solution, rhs and boundary conditions for the poisson problem +import numpy as np +import tensorflow as tf + + +def left_boundary(x, y): + """ + This function will return the boundary value for given component of a boundary + """ + return 0.0 + + +def right_boundary(x, y): + """ + This function will return the boundary value for given component of a boundary + """ + val = 0.0 + return val + + +def top_boundary(x, y): + """ + This function will return the boundary value for given component of a boundary + """ + val = 0.0 + return np.ones_like(x) * val + + +def bottom_boundary(x, y): + """ + This function will return the boundary value for given component of a boundary + """ + return 0.0 + + +def rhs(x, y): + """ + This function will return the value of the rhs at a given point + """ + # f_temp = 32 * (x * (1 - x) + y * (1 - y)) + # f_temp = 1 + + omegaX = 4.0 * np.pi + omegaY = 4.0 * np.pi + f_temp = -2.0 * (omegaX**2) * (np.sin(omegaX * x) * np.sin(omegaY * y)) + + return f_temp + + +def exact_solution(x, y): + """ + This function will return the exact solution at a given point + """ + + # val = 16 * x * (1 - x) * y * (1 - y) + omegaX = 4.0 * np.pi + omegaY = 4.0 * np.pi + val = -1.0 * np.sin(omegaX * x) * np.sin(omegaY * y) + + return val + + +def get_boundary_function_dict(): + """ + This function will return a dictionary of boundary functions + """ + return {1000: bottom_boundary, 1001: right_boundary, 1002: top_boundary, 1003: left_boundary} + + +def get_bound_cond_dict(): + """ + This function will return a dictionary of boundary conditions + """ + return {1000: "dirichlet", 1001: "dirichlet", 1002: "dirichlet", 1003: "dirichlet"} + + +def get_bilinear_params_dict(): + """ + This function will return a dictionary of bilinear parameters + """ + eps = 1.0 + + return {"eps": eps} diff --git a/examples/forward_problems_2d/uniform_mesh/poisson_2d/utility.py b/examples/forward_problems_2d/uniform_mesh/poisson_2d/utility.py new file mode 100644 index 0000000..794a0ea --- /dev/null +++ b/examples/forward_problems_2d/uniform_mesh/poisson_2d/utility.py @@ -0,0 +1,113 @@ +import sys +import yaml +import numpy as np + +from fastvpinns.utils.plot_utils import plot_contour, plot_loss_function, plot_test_loss_function +from fastvpinns.utils.compute_utils import compute_errors_combined + + +def get_errors( + model, + console, + y_pred, + y_exact, + Y_Exact_Matrix, + i_n_test_points_x, + i_n_test_points_y, + i_output_path, + epoch, + loss, + num_epochs, +): + """ + Calculate and return various error metrics and loss values. + + Args: + model (object): The trained model. + console (object): The console object for printing messages. + y_exact (array): The exact solution. + Y_Exact_Matrix (array): The matrix of exact solutions. + i_n_test_points_x (int): The number of test points in the x-direction. + i_n_test_points_y (int): The number of test points in the y-direction. + i_output_path (str): The output path for saving plots. + epoch (int): The current epoch number. + loss (dict): The dictionary containing different loss values. + num_epochs (int): The total number of epochs. + + Returns: + dict: A dictionary containing various error metrics and loss values. + """ + + # Compute error metrics + l2_error, linf_error, l2_error_relative, linf_error_relative, l1_error, l1_error_relative = ( + compute_errors_combined(y_exact, y_pred) + ) + + # Print epoch information + console.print(f"\nEpoch [bold]{epoch+1}/{num_epochs}[/bold]") + console.print("[bold]--------------------[/bold]") + console.print( + f"Variational Losses || Pde Loss : [red]{loss_pde:.3e}[/red] Dirichlet Loss : [red]{loss_dirichlet:.3e}[/red] Total Loss : [red]{total_loss:.3e}[/red]" + ) + console.print(f"Test Losses || L1 Error : {l1_error:.3e}", end=" ") + console.print(f"L2 Error : {l2_error:.3e}", end=" ") + console.print(f"Linf Error : {linf_error:.3e}", end="\n") + + return { + 'l2_error': l2_error, + 'linf_error': linf_error, + 'l2_error_relative': l2_error_relative, + 'linf_error_relative': linf_error_relative, + 'l1_error': l1_error, + 'l1_error_relative': l1_error_relative, + 'loss_pde': loss_pde, + 'loss_dirichlet': loss_dirichlet, + 'total_loss': total_loss, + } + + +def plot_results( + loss_array, + test_loss_array, + y_pred, + X, + Y, + Y_Exact_Matrix, + i_output_path, + epoch, + i_n_test_points_x, + i_n_test_points_y, +): + """ + Plot the loss function, test loss function, solution, and error. + + Args: + loss_array (array): Array of loss values during training. + test_loss_array (array): Array of test loss values during training. + y_pred (array): Predicted solution. + X (array): X-coordinates of the grid. + Y (array): Y-coordinates of the grid. + Y_Exact_Matrix (array): Matrix of exact solutions. + i_output_path (str): Output path for saving plots. + epoch (int): Current epoch number. + i_n_test_points_x (int): Number of test points in the x-direction. + i_n_test_points_y (int): Number of test points in the y-direction. + """ + # plot loss + plot_loss_function(loss_array, i_output_path) # plots NN loss + plot_test_loss_function(test_loss_array, i_output_path) # plots test loss + + # plot solution + y_pred = y_pred.reshape(i_n_test_points_x, i_n_test_points_y) + error = np.abs(Y_Exact_Matrix - y_pred) + plot_contour( + x=X, + y=Y, + z=y_pred, + output_path=i_output_path, + filename=f"prediction_{epoch+1}", + title="Prediction", + ) + plot_contour( + x=X, y=Y, z=error, output_path=i_output_path, filename=f"error_{epoch+1}", title="Error" + )