diff --git a/.buildinfo b/.buildinfo new file mode 100644 index 0000000..8b8b860 --- /dev/null +++ b/.buildinfo @@ -0,0 +1,4 @@ +# Sphinx build info version 1 +# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. +config: e9259293e3959cef89fe618c7445ba31 +tags: 645f666f9bcd5a90fca523b33c5a78b7 diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 0000000..e69de29 diff --git a/_images/epsilon_error.png b/_images/epsilon_error.png new file mode 100644 index 0000000..2cf3970 Binary files /dev/null and b/_images/epsilon_error.png differ diff --git a/_images/epsilon_exact.png b/_images/epsilon_exact.png new file mode 100644 index 0000000..b32374d Binary files /dev/null and b/_images/epsilon_exact.png differ diff --git a/_images/epsilon_predicted.png b/_images/epsilon_predicted.png new file mode 100644 index 0000000..cbac6f7 Binary files /dev/null and b/_images/epsilon_predicted.png differ diff --git a/_images/error.png b/_images/error.png new file mode 100644 index 0000000..aa0d721 Binary files /dev/null and b/_images/error.png differ diff --git a/_images/error1.png b/_images/error1.png new file mode 100644 index 0000000..4305ad1 Binary files /dev/null and b/_images/error1.png differ diff --git a/_images/error2.png b/_images/error2.png new file mode 100644 index 0000000..6386245 Binary files /dev/null and b/_images/error2.png differ diff --git a/_images/error3.png b/_images/error3.png new file mode 100644 index 0000000..28d3c74 Binary files /dev/null and b/_images/error3.png differ diff --git a/_images/error4.png b/_images/error4.png new file mode 100644 index 0000000..f918c00 Binary files /dev/null and b/_images/error4.png differ diff --git a/_images/error5.png b/_images/error5.png new file mode 100644 index 0000000..1a24bd4 Binary files /dev/null and b/_images/error5.png differ diff --git a/_images/error6.png b/_images/error6.png new file mode 100644 index 0000000..08914d5 Binary files /dev/null and b/_images/error6.png differ diff --git a/_images/error7.png b/_images/error7.png new file mode 100644 index 0000000..23aa2eb Binary files /dev/null and b/_images/error7.png differ diff --git a/_images/error8.png b/_images/error8.png new file mode 100644 index 0000000..f204a24 Binary files /dev/null and b/_images/error8.png differ diff --git a/_images/exact_solution.png b/_images/exact_solution.png new file mode 100644 index 0000000..30f4273 Binary files /dev/null and b/_images/exact_solution.png differ diff --git a/_images/exact_solution1.png b/_images/exact_solution1.png new file mode 100644 index 0000000..2e0424d Binary files /dev/null and b/_images/exact_solution1.png differ diff --git a/_images/exact_solution2.png b/_images/exact_solution2.png new file mode 100644 index 0000000..603dac6 Binary files /dev/null and b/_images/exact_solution2.png differ diff --git a/_images/exact_solution3.png b/_images/exact_solution3.png new file mode 100644 index 0000000..b654e3c Binary files /dev/null and b/_images/exact_solution3.png differ diff --git a/_images/exact_solution4.png b/_images/exact_solution4.png new file mode 100644 index 0000000..cb37cd8 Binary files /dev/null and b/_images/exact_solution4.png differ diff --git a/_images/exact_solution5.png b/_images/exact_solution5.png new file mode 100644 index 0000000..bb47d84 Binary files /dev/null and b/_images/exact_solution5.png differ diff --git a/_images/exact_solution6.png b/_images/exact_solution6.png new file mode 100644 index 0000000..0d64ae5 Binary files /dev/null and b/_images/exact_solution6.png differ diff --git a/_images/exact_solution7.png b/_images/exact_solution7.png new file mode 100644 index 0000000..0966ee8 Binary files /dev/null and b/_images/exact_solution7.png differ diff --git a/_images/exact_solution8.png b/_images/exact_solution8.png new file mode 100644 index 0000000..d1e4621 Binary files /dev/null and b/_images/exact_solution8.png differ diff --git a/_images/gmeshcircle.png b/_images/gmeshcircle.png new file mode 100644 index 0000000..155c62f Binary files /dev/null and b/_images/gmeshcircle.png differ diff --git a/_images/inverse_eps_prediction.png b/_images/inverse_eps_prediction.png new file mode 100644 index 0000000..d0ce0d6 Binary files /dev/null and b/_images/inverse_eps_prediction.png differ diff --git a/_images/loss_function.png b/_images/loss_function.png new file mode 100644 index 0000000..e98cb60 Binary files /dev/null and b/_images/loss_function.png differ diff --git a/_images/mesh.png b/_images/mesh.png new file mode 100644 index 0000000..8d5bc60 Binary files /dev/null and b/_images/mesh.png differ diff --git a/_images/mesh1.png b/_images/mesh1.png new file mode 100644 index 0000000..c4a957b Binary files /dev/null and b/_images/mesh1.png differ diff --git a/_images/mesh2.png b/_images/mesh2.png new file mode 100644 index 0000000..8d5bc60 Binary files /dev/null and b/_images/mesh2.png differ diff --git a/_images/mesh3.png b/_images/mesh3.png new file mode 100644 index 0000000..8d5bc60 Binary files /dev/null and b/_images/mesh3.png differ diff --git a/_images/mesh4.png b/_images/mesh4.png new file mode 100644 index 0000000..8d5bc60 Binary files /dev/null and b/_images/mesh4.png differ diff --git a/_images/predicted_solution.png b/_images/predicted_solution.png new file mode 100644 index 0000000..e96f1e9 Binary files /dev/null and b/_images/predicted_solution.png differ diff --git a/_images/predicted_solution1.png b/_images/predicted_solution1.png new file mode 100644 index 0000000..3660d16 Binary files /dev/null and b/_images/predicted_solution1.png differ diff --git a/_images/predicted_solution2.png b/_images/predicted_solution2.png new file mode 100644 index 0000000..cc28769 Binary files /dev/null and b/_images/predicted_solution2.png differ diff --git a/_images/predicted_solution3.png b/_images/predicted_solution3.png new file mode 100644 index 0000000..06588d6 Binary files /dev/null and b/_images/predicted_solution3.png differ diff --git a/_images/predicted_solution4.png b/_images/predicted_solution4.png new file mode 100644 index 0000000..fb33dc0 Binary files /dev/null and b/_images/predicted_solution4.png differ diff --git a/_images/predicted_solution5.png b/_images/predicted_solution5.png new file mode 100644 index 0000000..b4cf3d7 Binary files /dev/null and b/_images/predicted_solution5.png differ diff --git a/_images/predicted_solution6.png b/_images/predicted_solution6.png new file mode 100644 index 0000000..fa1b23e Binary files /dev/null and b/_images/predicted_solution6.png differ diff --git a/_images/predicted_solution7.png b/_images/predicted_solution7.png new file mode 100644 index 0000000..905589c Binary files /dev/null and b/_images/predicted_solution7.png differ diff --git a/_images/predicted_solution8.png b/_images/predicted_solution8.png new file mode 100644 index 0000000..03dacde Binary files /dev/null and b/_images/predicted_solution8.png differ diff --git a/_images/rect.png b/_images/rect.png new file mode 100644 index 0000000..b974cc2 Binary files /dev/null and b/_images/rect.png differ diff --git a/_images/rect1.png b/_images/rect1.png new file mode 100644 index 0000000..b974cc2 Binary files /dev/null and b/_images/rect1.png differ diff --git a/_images/rect2.png b/_images/rect2.png new file mode 100644 index 0000000..b974cc2 Binary files /dev/null and b/_images/rect2.png differ diff --git a/_images/rect3.png b/_images/rect3.png new file mode 100644 index 0000000..b974cc2 Binary files /dev/null and b/_images/rect3.png differ diff --git a/_images/unitcircle.png b/_images/unitcircle.png new file mode 100644 index 0000000..1b0a94d Binary files /dev/null and b/_images/unitcircle.png differ diff --git a/_images/unitcircle1.png b/_images/unitcircle1.png new file mode 100644 index 0000000..1b0a94d Binary files /dev/null and b/_images/unitcircle1.png differ diff --git a/_images/unitcircle2.png b/_images/unitcircle2.png new file mode 100644 index 0000000..1b0a94d Binary files /dev/null and b/_images/unitcircle2.png differ diff --git a/_images/unitcircle3.png b/_images/unitcircle3.png new file mode 100644 index 0000000..1b0a94d Binary files /dev/null and b/_images/unitcircle3.png differ diff --git a/_images/vpinns.png b/_images/vpinns.png new file mode 100644 index 0000000..fa2cdde Binary files /dev/null and b/_images/vpinns.png differ diff --git a/_modules/fastvpinns/FE/FE2D_Cell.html b/_modules/fastvpinns/FE/FE2D_Cell.html new file mode 100644 index 0000000..10f7a2a --- /dev/null +++ b/_modules/fastvpinns/FE/FE2D_Cell.html @@ -0,0 +1,432 @@ + + + + + + fastvpinns.FE.FE2D_Cell — fastvpinns 1.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for fastvpinns.FE.FE2D_Cell

+# This program will be used to setup the FE2D and quadrature rule for a given cell based on the
+# given mesh and the degree of the basis functions
+
+# Author: Thivin Anandh D
+# Date:  30/Aug/2023
+# Implementation History :
+# the grad_x_orig and grad_y_orig will actually store the magnitute with which we need to multiply this grad_x_ref and grad_y_ref
+# to obtain the actual values of the gradient in the original cell
+# this is done to improve efficiency
+
+
+# Importing the required libraries
+# from .basis_function_2d import *
+
+# import Quadrature rules
+from .quadratureformulas_quad2d import *
+from .fe2d_setup_main import *
+
+
+
+[docs] +class FE2D_Cell: + """ + This class is used to Store the FE Values, Such as Coordinates, Basis Functions, Quadrature Rules, etc. for a given cell. + """ + + def __init__( + self, + cell_coordinates: np.ndarray, + cell_type: str, + fe_order: int, + fe_type: str, + quad_order: int, + quad_type: str, + fe_transformation_type: str, + forcing_function, + ): + self.cell_coordinates = cell_coordinates + self.cell_type = cell_type + self.fe_order = fe_order + self.fe_type = fe_type + self.quad_order = quad_order + self.quad_type = quad_type + self.fe_transformation = fe_transformation_type + self.forcing_function = forcing_function + + # Basis function Class + self.basis_function = None + + # Quadrature Values + self.quad_xi = None + self.quad_eta = None + self.quad_weight = None + self.jacobian = None + self.mult = None + + # FE Values + self.basis_at_quad = None + self.basis_gradx_at_quad = None + self.basis_grady_at_quad = None + self.basis_gradxy_at_quad = None + self.basis_gradxx_at_quad = None + self.basis_gradyy_at_quad = None + + # Quadrature Coordinates + self.quad_actual_coordinates = None + + # Forcing function values at the quadrature points + self.forcing_at_quad = None + + # FE Transformation Class + self.fetransformation = None + + # get instance of the FE_setup class + self.fe_setup = FE2DSetupMain( + cell_type=self.cell_type, + fe_order=self.fe_order, + fe_type=self.fe_type, + quad_order=self.quad_order, + quad_type=self.quad_type, + ) + + # Call the function to assign the basis function + self.assign_basis_function() + + # Assign the quadrature points and weights + self.assign_quadrature() + + # Assign the FE Transformation + self.assign_fe_transformation() + + # calculate mult -> quadrature weights * Jacobian + self.assign_quad_weights_and_jacobian() + + # Calculate the basis function values at the quadrature points + self.assign_basis_values_at_quadrature_points() + + # calculate the actual coordinates of the quadrature points + self.assign_quadrature_coordinates() + + # Calculate the forcing function values at the actual quadrature points + # NOTE : The function is just for printing the shape of the force matrix, the + # actual calculation is performed on the fespace class + self.assign_forcing_term(self.forcing_function) + + # # print the values + # print("============================================================================") + # print("Cell Co-ord : ", self.cell_coordinates) + # print("Basis function values at the quadrature points: \n", self.basis_at_quad / self.mult) + # print("Basis function gradx at the quadrature points: \n", self.basis_gradx_at_quad) + # print("Basis function grady at the quadrature points: \n", self.basis_grady_at_quad) + # print("Forcing function values at the quadrature points: \n", self.forcing_at_quad) + + # grad_x = np.array([5,6,7,8]) + # grad_y = np.array([1,2,3,4]) + + # pde = np.matmul(self.basis_gradx_at_quad, grad_x.reshape(-1,1)) + np.matmul(self.basis_grady_at_quad, grad_y.reshape(-1,1)) + # print("PDE values at the quadrature points: \n", pde) + +
+[docs] + def assign_basis_function(self) -> BasisFunction2D: + """ + Assigns the basis function class based on the cell type and the FE order. + + :return: An instance of the BasisFunction2D class. + """ + self.basis_function = self.fe_setup.assign_basis_function()
+ + +
+[docs] + def assign_quadrature(self) -> None: + """ + Assigns the quadrature points and weights based on the cell type and the quadrature order. + + :return: None + """ + self.quad_weight, self.quad_xi, self.quad_eta = self.fe_setup.assign_quadrature_rules()
+ + +
+[docs] + def assign_fe_transformation(self) -> None: + """ + Assigns the FE Transformation class based on the cell type and the FE order. + + This method assigns the appropriate FE Transformation class based on the cell type and the FE order. + It sets the cell coordinates for the FE Transformation and obtains the Jacobian of the transformation. + + :return: None + """ + self.fetransformation = self.fe_setup.assign_fe_transformation( + self.fe_transformation, self.cell_coordinates + ) + # Sets cell co-ordinates for the FE Transformation + self.fetransformation.set_cell() + + # obtains the Jacobian of the transformation + self.jacobian = self.fetransformation.get_jacobian(self.quad_xi, self.quad_eta).reshape( + -1, 1 + )
+ + +
+[docs] + def assign_basis_values_at_quadrature_points(self) -> None: + """ + Assigns the basis function values at the quadrature points. + + This method calculates the values of the basis functions and their gradients at the quadrature points. + The basis function values are stored in `self.basis_at_quad`, while the gradients are stored in + `self.basis_gradx_at_quad`, `self.basis_grady_at_quad`, `self.basis_gradxy_at_quad`, + `self.basis_gradxx_at_quad`, and `self.basis_gradyy_at_quad`. + + The basis function values are of size N_basis_functions x N_quad_points. + + Returns: + None + """ + self.basis_at_quad = [] + self.basis_gradx_at_quad = [] + self.basis_grady_at_quad = [] + self.basis_gradxy_at_quad = [] + self.basis_gradxx_at_quad = [] + self.basis_gradyy_at_quad = [] + + self.basis_at_quad = self.basis_function.value(self.quad_xi, self.quad_eta) + + # For Gradients we need to perform a transformation to the original cell + grad_x_ref = self.basis_function.gradx(self.quad_xi, self.quad_eta) + grad_y_ref = self.basis_function.grady(self.quad_xi, self.quad_eta) + + grad_x_orig, grad_y_orig = self.fetransformation.get_orig_from_ref_derivative( + grad_x_ref, grad_y_ref, self.quad_xi, self.quad_eta + ) + + self.basis_gradx_at_quad = grad_x_orig + self.basis_grady_at_quad = grad_y_orig + + self.basis_gradx_at_quad_ref = grad_x_ref + self.basis_grady_at_quad_ref = grad_y_ref + + # get the double derivatives of the basis functions ( ref co-ordinates ) + grad_xx_ref = self.basis_function.gradxx(self.quad_xi, self.quad_eta) + grad_xy_ref = self.basis_function.gradxy(self.quad_xi, self.quad_eta) + grad_yy_ref = self.basis_function.gradyy(self.quad_xi, self.quad_eta) + + # get the double derivatives of the basis functions ( orig co-ordinates ) + grad_xx_orig, grad_xy_orig, grad_yy_orig = ( + self.fetransformation.get_orig_from_ref_second_derivative( + grad_xx_ref, grad_xy_ref, grad_yy_ref, self.quad_xi, self.quad_eta + ) + ) + + # = the value + self.basis_gradxy_at_quad = grad_xy_orig + self.basis_gradxx_at_quad = grad_xx_orig + self.basis_gradyy_at_quad = grad_yy_orig + + # Multiply each row with the quadrature weights + # Basis at Quad - n_test * N_quad + self.basis_at_quad = self.basis_at_quad * self.mult + self.basis_gradx_at_quad = self.basis_gradx_at_quad * self.mult + self.basis_grady_at_quad = self.basis_grady_at_quad * self.mult + self.basis_gradxy_at_quad = self.basis_gradxy_at_quad * self.mult + self.basis_gradxx_at_quad = self.basis_gradxx_at_quad * self.mult + self.basis_gradyy_at_quad = self.basis_gradyy_at_quad * self.mult
+ + +
+[docs] + def assign_quad_weights_and_jacobian(self) -> None: + """ + Assigns the quadrature weights and the Jacobian of the transformation. + + This method calculates and assigns the quadrature weights and the Jacobian of the transformation + for the current cell. The quadrature weights are multiplied by the flattened Jacobian array + and stored in the `mult` attribute of the class. + + :return: None + """ + self.mult = self.quad_weight * self.jacobian.flatten()
+ + +
+[docs] + def assign_quadrature_coordinates(self) -> None: + """ + Assigns the actual coordinates of the quadrature points. + + This method calculates the actual coordinates of the quadrature points based on the given Xi and Eta values. + The Xi and Eta values are obtained from the `quad_xi` and `quad_eta` attributes of the class. + The calculated coordinates are stored in the `quad_actual_coordinates` attribute as a NumPy array. + + :return: None + """ + actual_co_ord = [] + for xi, eta in zip(self.quad_xi, self.quad_eta): + actual_co_ord.append(self.fetransformation.get_original_from_ref(xi, eta)) + + self.quad_actual_coordinates = np.array(actual_co_ord)
+ + +
+[docs] + def assign_forcing_term(self, forcing_function) -> None: + """ + Assigns the forcing function values at the quadrature points. + + This function computes the values of the forcing function at the quadrature points + and assigns them to the `forcing_at_quad` attribute of the FE2D_Cell object. + + Parameters: + forcing_function (callable): The forcing function that takes the coordinates (x, y) + as input and returns the value of the forcing function at those coordinates. + + Returns: + None + + Notes: + - The final shape of `forcing_at_quad` will be N_shape_functions x 1. + - This function is for backward compatibility with old code and currently assigns + the values as zeros. The actual calculation is performed in the fespace class. + """ + # get number of shape functions + n_shape_functions = self.basis_function.num_shape_functions + + # Loop over all the basis functions and compute the integral + f_integral = np.zeros((n_shape_functions, 1), dtype=np.float64) + + # The above code is for backward compatibility with old code. this function will just assign the values as zeros + # the actual calculation is performed in the fespace class + + # for i in range(n_shape_functions): + # val = 0 + # for q in range(self.basis_at_quad.shape[1]): + # x = self.quad_actual_coordinates[q, 0] + # y = self.quad_actual_coordinates[q, 1] + # # print("f_values[q] = ",f_values[q]) + + # # the JAcobian and the quadrature weights are pre multiplied to the basis functions + # val += ( self.basis_at_quad[i, q] ) * self.forcing_function(x, y) + # # print("val = ", val) + + # f_integral[i] = val + + self.forcing_at_quad = f_integral
+
+ +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/fastvpinns/FE/basis_2d_QN_Jacobi.html b/_modules/fastvpinns/FE/basis_2d_QN_Jacobi.html new file mode 100644 index 0000000..c931aee --- /dev/null +++ b/_modules/fastvpinns/FE/basis_2d_QN_Jacobi.html @@ -0,0 +1,455 @@ + + + + + + fastvpinns.FE.basis_2d_QN_Jacobi — fastvpinns 1.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + + +
  • +
  • +
+
+
+
+
+ +

Source code for fastvpinns.FE.basis_2d_QN_Jacobi

+"""
+file: basis_2d_QN_Jacobi.py
+description: This file contains the class Basis2DQNJacobi which is used 
+             to define the basis functions for a Jacobi Polynomial.
+             Test functions and derivatives are inferred from the work by Ehsan Kharazmi et.al
+             (hp-VPINNs: Variational Physics-Informed Neural Networks With Domain Decomposition)
+             available at https://github.com/ehsankharazmi/hp-VPINNs/
+authors: Thivin Anandh D
+changelog: 30/Aug/2023 - Initial version
+known_issues: None
+dependencies: Requires scipy and numpy.
+"""
+
+# import the jacobi polynomials
+from scipy.special import jacobi
+
+import numpy as np
+from .basis_function_2d import BasisFunction2D
+
+
+
+[docs] +class Basis2DQNJacobi(BasisFunction2D): + """ + This class defines the basis functions for a 2D Q1 element. + """ + + def __init__(self, num_shape_functions: int): + super().__init__(num_shape_functions) + +
+[docs] + def jacobi_wrapper(self, n, a, b, x): + """ + Evaluate the Jacobi polynomial of degree n with parameters a and b at the given points x. + + :param n: Degree of the Jacobi polynomial. + :type n: int + :param a: First parameter of the Jacobi polynomial. + :type a: float + :param b: Second parameter of the Jacobi polynomial. + :type b: float + :param x: Points at which to evaluate the Jacobi polynomial. + :type x: array_like + + :return: Values of the Jacobi polynomial at the given points x. + :rtype: array_like + """ + x = np.array(x, dtype=np.float64) + return jacobi(n, a, b)(x)
+ + + # Derivative of the Jacobi polynomials +
+[docs] + def djacobi(self, n, a, b, x, k: int): + """ + Evaluate the k-th derivative of the Jacobi polynomial of degree n with parameters a and b at the given points x. + + :param n: Degree of the Jacobi polynomial. + :type n: int + :param a: First parameter of the Jacobi polynomial. + :type a: float + :param b: Second parameter of the Jacobi polynomial. + :type b: float + :param x: Points at which to evaluate the Jacobi polynomial. + :type x: array_like + :param k: Order of the derivative. + :type k: int + + :return: Values of the k-th derivative of the Jacobi polynomial at the given points x. + :rtype: array_like + + :raises ValueError: If the derivative order is not 1 or 2. + + :raises ImportError: If the required module 'jacobi' is not found. + + :raises Exception: If an unknown error occurs during the computation. + """ + x = np.array(x, dtype=np.float64) + if k == 1: + return jacobi(n, a, b).deriv()(x) + if k == 2: + return jacobi(n, a, b).deriv(2)(x) + else: + print(f"Invalid derivative order {k} in {__name__}.") + raise ValueError("Derivative order should be 1 or 2.")
+ + + ## Helper Function +
+[docs] + def test_fcnx(self, n_test, x): + """ + Compute the x-component of the test functions for a given number of test functions and x-coordinates. + + :param n_test: Number of test functions. + :type n_test: int + :param x: x-coordinates at which to evaluate the test functions. + :type x: array_like + + :return: Values of the x-component of the test functions. + :rtype: array_like + """ + test_total = [] + for n in range(1, n_test + 1): + test = self.jacobi_wrapper(n - 1, 0, 0, x) + test_total.append(test) + return np.asarray(test_total, np.float64)
+ + +
+[docs] + def test_fcny(self, n_test, y): + """ + Compute the y-component of the test functions for a given number of test functions and y-coordinates. + + Parameters: + n_test (int): Number of test functions. + y (array_like): y-coordinates at which to evaluate the test functions. + + Returns: + array_like: Values of the y-component of the test functions. + """ + test_total = [] + for n in range(1, n_test + 1): + test = self.jacobi_wrapper(n - 1, 0, 0, y) + test_total.append(test) + return np.asarray(test_total, np.float64)
+ + +
+[docs] + def dtest_fcn(self, n_test, x): + """ + Compute the x-derivatives of the test functions for a given number of test functions and x-coordinates. + + :param n_test: Number of test functions. + :type n_test: int + :param x: x-coordinates at which to evaluate the test functions. + :type x: array_like + + :return: Values of the x-derivatives of the test functions. + :rtype: array_like + """ + d1test_total = [] + for n in range(1, n_test + 1): + d1test = self.djacobi(n - 1, 0, 0, x, 1) + d1test_total.append(d1test) + return np.asarray(d1test_total)
+ + +
+[docs] + def ddtest_fcn(self, n_test, x): + """ + Compute the x-derivatives of the test functions for a given number of test functions and x-coordinates. + + :param n_test: Number of test functions. + :type n_test: int + :param x: x-coordinates at which to evaluate the test functions. + :type x: array_like + + :return: Values of the x-derivatives of the test functions. + :rtype: array_like + """ + d1test_total = [] + for n in range(1, n_test + 1): + d1test = self.djacobi(n - 1, 0, 0, x, 2) + d1test_total.append(d1test) + return np.asarray(d1test_total)
+ + +
+[docs] + def value(self, xi, eta): + """ + This method returns the values of the basis functions at the given (xi, eta) coordinates. + + :param xi: x-coordinates at which to evaluate the basis functions. + :type xi: array_like + :param eta: y-coordinates at which to evaluate the basis functions. + :type eta: array_like + :return: Values of the basis functions. + :rtype: array_like + """ + num_shape_func_in_1d = int(np.sqrt(self.num_shape_functions)) + test_x = self.test_fcnx(num_shape_func_in_1d, xi) + test_y = self.test_fcny(num_shape_func_in_1d, eta) + values = np.zeros((self.num_shape_functions, len(xi)), dtype=np.float64) + + for i in range(num_shape_func_in_1d): + values[num_shape_func_in_1d * i : num_shape_func_in_1d * (i + 1), :] = ( + test_x[i, :] * test_y + ) + + return values
+ + +
+[docs] + def gradx(self, xi, eta): + """ + This method returns the x-derivatives of the basis functions at the given (xi, eta) coordinates. + + :param xi: x-coordinates at which to evaluate the basis functions. + :type xi: array_like + :param eta: y-coordinates at which to evaluate the basis functions. + :type eta: array_like + :return: Values of the x-derivatives of the basis functions. + :rtype: array_like + """ + num_shape_func_in_1d = int(np.sqrt(self.num_shape_functions)) + grad_test_x = self.dtest_fcn(num_shape_func_in_1d, xi) + test_y = self.test_fcny(num_shape_func_in_1d, eta) + values = np.zeros((self.num_shape_functions, len(xi)), dtype=np.float64) + + for i in range(num_shape_func_in_1d): + values[num_shape_func_in_1d * i : num_shape_func_in_1d * (i + 1), :] = ( + grad_test_x[i, :] * test_y + ) + + return values
+ + +
+[docs] + def grady(self, xi, eta): + """ + This method returns the y-derivatives of the basis functions at the given (xi, eta) coordinates. + + :param xi: x-coordinates at which to evaluate the basis functions. + :type xi: array_like + + :param eta: y-coordinates at which to evaluate the basis functions. + :type eta: array_like + + :return: Values of the y-derivatives of the basis functions. + :rtype: array_like + """ + num_shape_func_in_1d = int(np.sqrt(self.num_shape_functions)) + test_x = self.test_fcnx(num_shape_func_in_1d, xi) + grad_test_y = self.dtest_fcn(num_shape_func_in_1d, eta) + values = np.zeros((self.num_shape_functions, len(xi)), dtype=np.float64) + + for i in range(num_shape_func_in_1d): + values[num_shape_func_in_1d * i : num_shape_func_in_1d * (i + 1), :] = ( + test_x[i, :] * grad_test_y + ) + + return values
+ + +
+[docs] + def gradxx(self, xi, eta): + """ + This method returns the xx-derivatives of the basis functions at the given (xi, eta) coordinates. + + :param xi: x-coordinates at which to evaluate the basis functions. + :type xi: array_like + :param eta: y-coordinates at which to evaluate the basis functions. + :type eta: array_like + + :return: Values of the xx-derivatives of the basis functions. + :rtype: array_like + """ + num_shape_func_in_1d = int(np.sqrt(self.num_shape_functions)) + grad_grad_x = self.ddtest_fcn(num_shape_func_in_1d, xi) + test_y = self.test_fcny(num_shape_func_in_1d, eta) + values = np.zeros((self.num_shape_functions, len(xi)), dtype=np.float64) + + for i in range(num_shape_func_in_1d): + values[num_shape_func_in_1d * i : num_shape_func_in_1d * (i + 1), :] = ( + grad_grad_x[i, :] * test_y + ) + + return values
+ + +
+[docs] + def gradxy(self, xi, eta): + """ + This method returns the xy-derivatives of the basis functions at the given (xi, eta) coordinates. + + :param xi: x-coordinates at which to evaluate the basis functions. + :type xi: array_like + :param eta: y-coordinates at which to evaluate the basis functions. + :type eta: array_like + :return: Values of the xy-derivatives of the basis functions. + :rtype: array_like + """ + num_shape_func_in_1d = int(np.sqrt(self.num_shape_functions)) + grad_test_x = self.dtest_fcn(num_shape_func_in_1d, xi) + grad_test_y = self.dtest_fcn(num_shape_func_in_1d, eta) + values = np.zeros((self.num_shape_functions, len(xi)), dtype=np.float64) + + for i in range(num_shape_func_in_1d): + values[num_shape_func_in_1d * i : num_shape_func_in_1d * (i + 1), :] = ( + grad_test_x[i, :] * grad_test_y + ) + + return values
+ + +
+[docs] + def gradyy(self, xi, eta): + """ + This method returns the yy-derivatives of the basis functions at the given (xi, eta) coordinates. + + :param xi: x-coordinates at which to evaluate the basis functions. + :type xi: array_like + :param eta: y-coordinates at which to evaluate the basis functions. + :type eta: array_like + + :return: Values of the yy-derivatives of the basis functions. + :rtype: array_like + """ + num_shape_func_in_1d = int(np.sqrt(self.num_shape_functions)) + test_x = self.test_fcnx(num_shape_func_in_1d, xi) + grad_grad_y = self.ddtest_fcn(num_shape_func_in_1d, eta) + values = np.zeros((self.num_shape_functions, len(xi)), dtype=np.float64) + + for i in range(num_shape_func_in_1d): + values[num_shape_func_in_1d * i : num_shape_func_in_1d * (i + 1), :] = ( + test_x[i, :] * grad_grad_y + ) + + return values
+
+ +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/fastvpinns/FE/fe2d_setup_main.html b/_modules/fastvpinns/FE/fe2d_setup_main.html new file mode 100644 index 0000000..4e9284d --- /dev/null +++ b/_modules/fastvpinns/FE/fe2d_setup_main.html @@ -0,0 +1,264 @@ + + + + + + fastvpinns.FE.fe2d_setup_main — fastvpinns 1.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + + +
  • +
  • +
+
+
+
+
+ +

Source code for fastvpinns.FE.fe2d_setup_main

+# This program will be used to setup the FE2D and quadrature rule for a given cell based on the
+# given mesh and the degree of the basis functions
+
+# Author: Thivin Anandh D
+# Date:  30/Aug/2023
+
+# Importing the required libraries
+from .basis_function_2d import *
+
+# import Quadrature rules
+from .quadratureformulas_quad2d import *
+
+
+# import base class for FE transformation
+from .fe_transformation_2d import *
+
+
+
+[docs] +class FE2DSetupMain: + """ + This class is used to setup the FE2D and quadrature rule for a given cell based on the given mesh and the degree of the basis functions. + """ + + def __init__( + self, cell_type: str, fe_order: int, fe_type: str, quad_order: int, quad_type: str + ): + self.cell_type = cell_type + self.fe_order = fe_order + self.fe_type = fe_type + self.quad_order = quad_order + self.quad_type = quad_type + + self.assign_basis_function() + +
+[docs] + def assign_basis_function(self) -> BasisFunction2D: + """ + Assigns the basis function based on the cell type and the fe_order. + + :return: An instance of the BasisFunction2D class representing the assigned basis function. + :rtype: BasisFunction2D + :raises ValueError: If the fe_order is invalid. + """ + # check for FE order lower bound and higher bound + if self.fe_order <= 1 or self.fe_order >= 1e3: + print(f"Invalid FE order {self.fe_order} in {self.__class__.__name__} from {__name__}.") + raise ValueError("FE order should be greater than 1 and less than 1e4.") + + if self.cell_type == "quadrilateral": + self.n_nodes = 4 + + # --- LEGENDRE --- # + if self.fe_type == "legendre" or self.fe_type == "jacobi": + # jacobi is added for backward compatibility with prev pushes + # generally, jacobi is referred to as Legendre basis on previous iterations + return Basis2DQNLegendre(self.fe_order**2) + + elif self.fe_type == "legendre_special": + return Basis2DQNLegendreSpecial(self.fe_order**2) + + # ----- CHEBYSHEV ---- # + elif self.fe_type == "chebyshev_2": + return Basis2DQNChebyshev2(self.fe_order**2) + + # ----- PLain jacobi ---- # + elif self.fe_type == "jacobi_plain": + return Basis2DQNJacobi(self.fe_order**2) + + else: + print( + f"Invalid FE order {self.fe_order} in {self.__class__.__name__} from {__name__}." + ) + raise ValueError( + 'FE order should be one of the : "legendre" , "jacobi", "legendre_special", "chebyshev_2", "jacobi_plain"' + ) + + print(f"Invalid cell type {self.cell_type} in {self.__class__.__name__} from {__name__}.")
+ + +
+[docs] + def assign_quadrature_rules(self): + """ + Assigns the quadrature rule based on the quad_order. + + :return: A tuple containing the weights, xi, and eta values of the quadrature rule. + :rtype: tuple + :raises ValueError: If the quad_order is invalid or the cell_type is invalid. + """ + if self.cell_type == "quadrilateral": + if self.quad_order < 3: + raise ValueError("Quad order should be greater than 2.") + elif self.quad_order >= 2 and self.quad_order <= 9999: + weights, xi, eta = Quadratureformulas_Quad2D( + self.quad_order, self.quad_type + ).get_quad_values() + return weights, xi, eta + else: + print( + f"Invalid quad order {self.quad_order} in {self.__class__.__name__} from {__name__}." + ) + raise ValueError("Quad order should be between 1 and 9999.") + + raise ValueError( + f"Invalid cell type {self.cell_type} in {self.__class__.__name__} from {__name__}." + )
+ + +
+[docs] + def assign_fe_transformation( + self, fe_transformation_type, cell_coordinates + ) -> FETransforamtion2D: + """ + Assigns the FE transformation based on the cell type. + + :param fe_transformation_type: The type of FE transformation. + :type fe_transformation_type: str + :param cell_coordinates: The coordinates of the cell. + :type cell_coordinates: list + :return: The FE transformation object. + :rtype: FETransforamtion2D + :raises ValueError: If the cell type or FE transformation type is invalid. + """ + if self.cell_type == "quadrilateral": + if fe_transformation_type == "affine": + return QuadAffin(cell_coordinates) + elif fe_transformation_type == "bilinear": + return QuadBilinear(cell_coordinates) + else: + raise ValueError( + f"Invalid FE transformation type {fe_transformation_type} in {self.__class__.__name__} from {__name__}." + ) + + else: + raise ValueError( + f"Invalid cell type {self.cell_type} in {self.__class__.__name__} from {__name__}." + )
+
+ +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/fastvpinns/FE/fe_transformation_2d.html b/_modules/fastvpinns/FE/fe_transformation_2d.html new file mode 100644 index 0000000..bd6f68a --- /dev/null +++ b/_modules/fastvpinns/FE/fe_transformation_2d.html @@ -0,0 +1,219 @@ + + + + + + fastvpinns.FE.fe_transformation_2d — fastvpinns 1.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + + +
  • +
  • +
+
+
+
+
+ +

Source code for fastvpinns.FE.fe_transformation_2d

+# This class provides an interface for the transformation methods used in the
+# 2D finite element analysis. The transformation is essential for mapping
+# element geometry in the reference domain to the actual physical domain.
+# The primary functionalities encapsulated within this class include:
+#   1. set_cell() - To set the physical coordinates of the cell. These coordinates
+#                   are essential for subsequent computations involving Jacobians and transformations.
+#   2. get_original_from_ref(xi, eta) - Given reference coordinates (xi, eta), this
+#                   method returns the corresponding coordinates in the physical domain.
+#   3. get_jacobian(xi, eta) - For a given point in the reference domain, represented
+#                   by (xi, eta), this method calculates and returns the Jacobian of
+#                   the transformation, which provides information about the local stretching,
+#                   rotation, and skewing of the element.
+#
+# Further implementations of this class for specific element types (like quad and triangular elements)
+# can incorporate more detailed and element-specific transformation techniques.
+#
+# Author: Thivin Anandh D
+# Date:   20-Sep-2023
+# History: First version -  20-Sep-2023 - Thivin Anandh
+
+
+from abc import abstractmethod
+
+
+
+[docs] +class FETransforamtion2D: + """ + This class represents a 2D finite element transformation. + """ + + def __init__(self): + """ + Constructor for the FETransforamtion2D class. + """ + +
+[docs] + @abstractmethod + def set_cell(self): + """ + Set the cell coordinates, which will be used to calculate the Jacobian and actual values. + + :return: None + """
+ + + @abstractmethod + def get_original_from_ref(self, xi, eta): + """ + This method returns the original coordinates from the reference coordinates. + + :param xi: The xi coordinate in the reference space. + :type xi: float + :param eta: The eta coordinate in the reference space. + :type eta: float + :return: The original coordinates (x, y) corresponding to the given reference coordinates. + :rtype: tuple + """ + +
+[docs] + @abstractmethod + def get_original_from_ref(self, xi, eta): + """ + This method returns the original coordinates from the reference coordinates. + + :param xi: The xi value of the reference coordinates. + :type xi: float + :param eta: The eta value of the reference coordinates. + :type eta: float + :return: The original coordinates corresponding to the given reference coordinates. + :rtype: tuple + """
+ + +
+[docs] + @abstractmethod + def get_jacobian(self, xi, eta): + """ + This method returns the Jacobian of the transformation. + + :param xi: The xi coordinate. + :type xi: float + :param eta: The eta coordinate. + :type eta: float + :return: The Jacobian matrix. + :rtype: numpy.ndarray + """
+
+ + + +## Mandatory, Import all the basis functions here (Quad element Transformations) +from .quad_affine import * +from .quad_bilinear import * +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/fastvpinns/FE/fespace.html b/_modules/fastvpinns/FE/fespace.html new file mode 100644 index 0000000..8fd665b --- /dev/null +++ b/_modules/fastvpinns/FE/fespace.html @@ -0,0 +1,418 @@ + + + + + + fastvpinns.FE.fespace — fastvpinns 1.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for fastvpinns.FE.fespace

+"""
+file: fespace.py
+description: Abstract class for the FEspace Routines
+authors: Thivin Anandh D
+changelog: 03-May-2024
+known_issues: None
+dependencies: None specified.
+"""
+
+import numpy as np
+from abc import abstractmethod
+
+
+
+[docs] +class Fespace: + """ + Represents a finite element space. + + :param mesh: The mesh object. + :type mesh: Mesh + :param cells: The array of cell indices. + :type cells: ndarray + :param boundary_points: The dictionary of boundary points. + :type boundary_points: dict + :param cell_type: The type of cell. + :type cell_type: str + :param fe_order: The order of the finite element. + :type fe_order: int + :param fe_type: The type of finite element. + :type fe_type: str + :param quad_order: The order of the quadrature. + :type quad_order: int + :param quad_type: The type of quadrature. + :type quad_type: str + :param fe_transformation_type: The type of finite element transformation. + :type fe_transformation_type: str + :param bound_function_dict: The dictionary of boundary functions. + :type bound_function_dict: dict + :param bound_condition_dict: The dictionary of boundary conditions. + :type bound_condition_dict: dict + :param forcing_function: The forcing function. + :type forcing_function: function + :param output_path: The output path. + :type output_path: str + :param generate_mesh_plot: Whether to generate a plot of the mesh. Defaults to False. + :type generate_mesh_plot: bool, optional + """ + + def __init__( + self, + mesh, + cells, + boundary_points, + cell_type: str, + fe_order: int, + fe_type: str, + quad_order: int, + quad_type: str, + fe_transformation_type: str, + bound_function_dict: dict, + bound_condition_dict: dict, + forcing_function, + output_path: str, + ) -> None: + """ + The constructor of the Fespace2D class. + """ + self.mesh = mesh + self.boundary_points = boundary_points + self.cells = cells + self.cell_type = cell_type + self.fe_order = fe_order + self.fe_type = fe_type + self.quad_order = quad_order + self.quad_type = quad_type + + self.fe_transformation_type = fe_transformation_type + self.output_path = output_path + self.bound_function_dict = bound_function_dict + self.bound_condition_dict = bound_condition_dict + self.forcing_function = forcing_function + +
+[docs] + @abstractmethod + def set_finite_elements(self) -> None: + """ + Assigns the finite elements to each cell. + + This method initializes the finite element objects for each cell in the mesh. + It creates an instance of the `FE2D_Cell` class for each cell, passing the necessary parameters. + The finite element objects store information about the basis functions, gradients, Jacobians, + quadrature points, weights, actual coordinates, and forcing functions associated with each cell. + + After initializing the finite element objects, this method prints the shape details of various matrices + and updates the total number of degrees of freedom (dofs) for the entire mesh. + + :return: None + """
+ + +
+[docs] + @abstractmethod + def generate_dirichlet_boundary_data(self) -> np.ndarray: + """ + Generate Dirichlet boundary data. + + This function returns the boundary points and their corresponding values. + + :return: A tuple containing two arrays: + - The first array contains the boundary points as numpy arrays. + - The second array contains the values of the boundary points as numpy arrays. + :rtype: Tuple[np.ndarray, np.ndarray] + """
+ + +
+[docs] + @abstractmethod + def get_shape_function_val(self, cell_index) -> np.ndarray: + """ + Get the actual values of the shape functions on a given cell. + + :param cell_index: The index of the cell. + :type cell_index: int + + :return: An array containing the actual values of the shape functions. + :rtype: np.ndarray + + :raises ValueError: If the cell_index is greater than the number of cells. + """
+ + +
+[docs] + @abstractmethod + def get_shape_function_grad_x(self, cell_index) -> np.ndarray: + """ + Get the gradient of the shape function with respect to the x-coordinate. + + :param cell_index: The index of the cell. + :type cell_index: int + + :return: An array containing the gradient of the shape function with respect to the x-coordinate. + :rtype: np.ndarray + + :raises ValueError: If the cell_index is greater than the number of cells. + + This function returns the actual values of the gradient of the shape function on a given cell. + """
+ + +
+[docs] + @abstractmethod + def get_shape_function_grad_x_ref(self, cell_index) -> np.ndarray: + """ + Get the gradient of the shape function with respect to the x-coordinate on the reference element. + + :param cell_index: The index of the cell. + :type cell_index: int + + :return: An array containing the gradient of the shape function with respect to the x-coordinate. + :rtype: np.ndarray + + :raises ValueError: If the cell_index is greater than the number of cells. + """
+ + +
+[docs] + @abstractmethod + def get_shape_function_grad_y(self, cell_index) -> np.ndarray: + """ + Get the gradient of the shape function with respect to y at the given cell index. + + :param cell_index: The index of the cell. + :type cell_index: int + + :return: The gradient of the shape function with respect to y. + :rtype: np.ndarray + + :raises ValueError: If the cell_index is greater than the total number of cells. + """
+ + +
+[docs] + @abstractmethod + def get_shape_function_grad_y_ref(self, cell_index): + """ + Get the gradient of the shape function with respect to y at the reference element. + + :param cell_index: The index of the cell. + :type cell_index: int + :return: The gradient of the shape function with respect to y at the reference element. + :rtype: np.ndarray + :raises ValueError: If cell_index is greater than the number of cells. + + This function returns the gradient of the shape function with respect to y at the reference element + for a given cell. The shape function gradient values are stored in the `basis_grady_at_quad_ref` array + of the corresponding finite element cell. The `cell_index` parameter specifies the index of the cell + for which the shape function gradient is required. If the `cell_index` is greater than the total number + of cells, a `ValueError` is raised. + + .. note:: + The returned gradient values are copied from the `basis_grady_at_quad_ref` array to ensure immutability. + """
+ + +
+[docs] + @abstractmethod + def get_quadrature_actual_coordinates(self, cell_index) -> np.ndarray: + """ + Get the actual coordinates of the quadrature points for a given cell. + + :param cell_index: The index of the cell. + :type cell_index: int + + :return: An array containing the actual coordinates of the quadrature points. + :rtype: np.ndarray + + :raises ValueError: If the cell_index is greater than the number of cells. + """
+ + +
+[docs] + @abstractmethod + def get_forcing_function_values(self, cell_index) -> np.ndarray: + """ + Get the forcing function values at the quadrature points. + + :param cell_index: The index of the cell. + :type cell_index: int + + :return: The forcing function values at the quadrature points. + :rtype: np.ndarray + + :raises ValueError: If cell_index is greater than the number of cells. + + This function computes the forcing function values at the quadrature points for a given cell. + It loops over all the basis functions and computes the integral using the actual coordinates + and the basis functions at the quadrature points. The resulting values are stored in the + `forcing_at_quad` attribute of the corresponding `fe_cell` object. + + Note: The forcing function is evaluated using the `forcing_function` method of the `fe_cell` + object. + """
+ + +
+[docs] + @abstractmethod + def get_sensor_data(self, exact_solution, num_points): + """ + Obtain sensor data (actual solution) at random points. + + This method is used in the inverse problem to obtain the sensor data at random points within the domain. + Currently, it only works for problems with an analytical solution. + Methodologies to obtain sensor data for problems from a file are not implemented yet. + It is also not implemented for external or complex meshes. + + :param exact_solution: A function that computes the exact solution at a given point. + :type exact_solution: function + :param num_points: The number of random points to generate. + :type num_points: int + :return: A tuple containing the generated points and the exact solution at those points. + :rtype: tuple(numpy.ndarray, numpy.ndarray) + """
+ + +
+[docs] + @abstractmethod + def get_sensor_data_external(self, exact_sol, num_points, file_name): + """ + This method is used to obtain the sensor data from an external file. + + :param exact_sol: The exact solution values. + :type exact_sol: array-like + :param num_points: The number of points to sample from the data. + :type num_points: int + :param file_name: The path to the file containing the sensor data. + :type file_name: str + + :return: A tuple containing two arrays: + - points (ndarray): The sampled points from the data. + - exact_sol (ndarray): The corresponding exact solution values. + :rtype: tuple + """
+
+ +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/fastvpinns/FE/fespace2d.html b/_modules/fastvpinns/FE/fespace2d.html new file mode 100644 index 0000000..fd350ca --- /dev/null +++ b/_modules/fastvpinns/FE/fespace2d.html @@ -0,0 +1,911 @@ + + + + + + fastvpinns.FE.fespace2d — fastvpinns 1.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for fastvpinns.FE.fespace2d

+"""
+file: fespace2d.py
+description: This file contains the main class that holds the information of all the 
+             Finite Element (FE) spaces of all the cells within the given mesh.
+authors: Thivin Anandh D
+changelog: 30/Aug/2023 - Initial version
+known_issues: None
+dependencies: None specified.
+"""
+
+import numpy as np
+import meshio
+from .FE2D_Cell import FE2D_Cell
+
+# from rich.progress import Progress, TextColumn, BarColumn, TimeElapsedColumn
+from tqdm import tqdm
+
+# import plotting
+import matplotlib.pyplot as plt
+
+# import path
+from pathlib import Path
+
+# import tensorflow
+import tensorflow as tf
+
+from ..utils.print_utils import print_table
+
+from pyDOE import lhs
+import pandas as pd
+
+from matplotlib import rc
+from cycler import cycler
+
+
+plt.rcParams["xtick.labelsize"] = 20
+plt.rcParams["axes.titlesize"] = 20
+plt.rcParams["axes.labelsize"] = 20
+
+plt.rcParams["legend.fontsize"] = 20
+plt.rcParams["ytick.labelsize"] = 20
+plt.rcParams["axes.prop_cycle"] = cycler(
+    color=[
+        "darkblue",
+        "#d62728",
+        "#2ca02c",
+        "#ff7f0e",
+        "#bcbd22",
+        "#8c564b",
+        "#17becf",
+        "#9467bd",
+        "#e377c2",
+        "#7f7f7f",
+    ]
+)
+
+from .fespace import Fespace
+
+
+
+[docs] +class Fespace2D(Fespace): + """ + Represents a finite element space in 2D. + + :param mesh: The mesh object. + :type mesh: Mesh + :param cells: The array of cell indices. + :type cells: ndarray + :param boundary_points: The dictionary of boundary points. + :type boundary_points: dict + :param cell_type: The type of cell. + :type cell_type: str + :param fe_order: The order of the finite element. + :type fe_order: int + :param fe_type: The type of finite element. + :type fe_type: str + :param quad_order: The order of the quadrature. + :type quad_order: int + :param quad_type: The type of quadrature. + :type quad_type: str + :param fe_transformation_type: The type of finite element transformation. + :type fe_transformation_type: str + :param bound_function_dict: The dictionary of boundary functions. + :type bound_function_dict: dict + :param bound_condition_dict: The dictionary of boundary conditions. + :type bound_condition_dict: dict + :param forcing_function: The forcing function. + :type forcing_function: function + :param output_path: The output path. + :type output_path: str + :param generate_mesh_plot: Whether to generate a plot of the mesh. Defaults to False. + :type generate_mesh_plot: bool, optional + """ + + def __init__( + self, + mesh, + cells, + boundary_points, + cell_type: str, + fe_order: int, + fe_type: str, + quad_order: int, + quad_type: str, + fe_transformation_type: str, + bound_function_dict: dict, + bound_condition_dict: dict, + forcing_function, + output_path: str, + generate_mesh_plot: bool = False, + ) -> None: + """ + The constructor of the Fespace2D class. + """ + # call the constructor of the parent class + super().__init__( + mesh=mesh, + cells=cells, + boundary_points=boundary_points, + cell_type=cell_type, + fe_order=fe_order, + fe_type=fe_type, + quad_order=quad_order, + quad_type=quad_type, + fe_transformation_type=fe_transformation_type, + bound_function_dict=bound_function_dict, + bound_condition_dict=bound_condition_dict, + forcing_function=forcing_function, + output_path=output_path, + ) + + if self.cell_type == "triangle": + raise ValueError( + "Triangle Mesh is not supported yet" + ) # added by thivin - to remove support for triangular mesh + + self.generate_mesh_plot = generate_mesh_plot + + # to be calculated in the plot function + self.total_dofs = 0 + self.total_boundary_dofs = 0 + + # to be calculated on get_boundary_data_dirichlet function + self.total_dirichlet_dofs = 0 + + # get the number of cells + self.n_cells = self.cells.shape[0] + + self.fe_cell = [] + + # Function which assigns the fe_cell for each cell + self.set_finite_elements() + + # generate the plot of the mesh + if self.generate_mesh_plot: + self.generate_plot(self.output_path) + # self.generate_plot(self.output_path) + + # Obtain boundary Data + self.dirichlet_boundary_data = self.generate_dirichlet_boundary_data() + + title = [ + "Number of Cells", + "Number of Quadrature Points", + "Number of Dirichlet Boundary Points", + "Quadrature Order", + "FE Order", + "FE Type", + "FE Transformation Type", + ] + values = [ + self.n_cells, + self.total_dofs, + self.total_dirichlet_dofs, + self.quad_order, + self.fe_order, + self.fe_type, + self.fe_transformation_type, + ] + # print the table + print_table("FE Space Information", ["Property", "Value"], title, values) + +
+[docs] + def set_finite_elements(self) -> None: + """ + Assigns the finite elements to each cell. + + This method initializes the finite element objects for each cell in the mesh. + It creates an instance of the `FE2D_Cell` class for each cell, passing the necessary parameters. + The finite element objects store information about the basis functions, gradients, Jacobians, + quadrature points, weights, actual coordinates, and forcing functions associated with each cell. + + After initializing the finite element objects, this method prints the shape details of various matrices + and updates the total number of degrees of freedom (dofs) for the entire mesh. + + :return: None + """ + progress_bar = tqdm( + total=self.n_cells, + desc="Fe2D_cell Setup", + unit="cells_assembled", + bar_format="{l_bar}{bar:40}{r_bar}{bar:-10b}", + colour="blue", + ncols=100, + ) + + dof = 0 + for i in range(self.n_cells): + self.fe_cell.append( + FE2D_Cell( + self.cells[i], + self.cell_type, + self.fe_order, + self.fe_type, + self.quad_order, + self.quad_type, + self.fe_transformation_type, + self.forcing_function, + ) + ) + + # obtain the shape of the basis function (n_test, N_quad) + dof += self.fe_cell[i].basis_at_quad.shape[1] + + progress_bar.update(1) + # print the Shape details of all the matrices from cell 0 using print_table function + title = [ + "Shape function Matrix Shape", + "Shape function Gradient Matrix Shape", + "Jacobian Matrix Shape", + "Quadrature Points Shape", + "Quadrature Weights Shape", + "Quadrature Actual Coordinates Shape", + "Forcing Function Shape", + ] + values = [ + self.fe_cell[0].basis_at_quad.shape, + self.fe_cell[0].basis_gradx_at_quad.shape, + self.fe_cell[0].jacobian.shape, + self.fe_cell[0].quad_xi.shape, + self.fe_cell[0].quad_weight.shape, + self.fe_cell[0].quad_actual_coordinates.shape, + self.fe_cell[0].forcing_at_quad.shape, + ] + print_table("FE Matrix Shapes", ["Matrix", "Shape"], title, values) + + # update the total number of dofs + self.total_dofs = dof
+ + +
+[docs] + def generate_plot(self, output_path) -> None: + """ + Generate a plot of the mesh. + + :param output_path: The path to save the generated plot. + :type output_path: str + """ + total_quad = 0 + marker_list = [ + "o", + ".", + ",", + "x", + "+", + "P", + "s", + "D", + "d", + "^", + "v", + "<", + ">", + "p", + "h", + "H", + ] + + print(f"[INFO] : Generating the plot of the mesh") + # Plot the mesh + plt.figure(figsize=(6.4, 4.8), dpi=300) + + # label flag ( to add the label only once) + label_set = False + + # plot every cell as a quadrilateral + # loop over all the cells + for i in range(self.n_cells): + # get the coordinates of the cell + x = self.fe_cell[i].cell_coordinates[:, 0] + y = self.fe_cell[i].cell_coordinates[:, 1] + + # add the first point to the end of the array + x = np.append(x, x[0]) + y = np.append(y, y[0]) + + plt.plot(x, y, "k-", linewidth=0.5) + + # plot the quadrature points + x_quad = self.fe_cell[i].quad_actual_coordinates[:, 0] + y_quad = self.fe_cell[i].quad_actual_coordinates[:, 1] + + total_quad += x_quad.shape[0] + + if not label_set: + plt.scatter(x_quad, y_quad, marker="x", color="b", s=2, label="Quad Pts") + label_set = True + else: + plt.scatter(x_quad, y_quad, marker="x", color="b", s=2) + + self.total_dofs = total_quad + + bound_dof = 0 + # plot the boundary points + # loop over all the boundary tags + for i, (bound_id, bound_pts) in enumerate(self.boundary_points.items()): + # get the coordinates of the boundary points + x = bound_pts[:, 0] + y = bound_pts[:, 1] + + # add the first point to the end of the array + x = np.append(x, x[0]) + y = np.append(y, y[0]) + + bound_dof += x.shape[0] + + plt.scatter(x, y, marker=marker_list[i + 1], s=2, label=f"Bd-id : {bound_id}") + + self.total_boundary_dofs = bound_dof + + plt.legend(bbox_to_anchor=(0.85, 1.02)) + plt.axis("equal") + plt.axis("off") + plt.tight_layout() + + plt.savefig(str(Path(output_path) / "mesh.png"), bbox_inches="tight") + plt.savefig(str(Path(output_path) / "mesh.svg"), bbox_inches="tight") + + # print the total number of quadrature points + print(f"Plots generated") + print(f"[INFO] : Total number of cells = {self.n_cells}") + print(f"[INFO] : Total number of quadrature points = {self.total_dofs}") + print(f"[INFO] : Total number of boundary points = {self.total_boundary_dofs}")
+ + +
+[docs] + def generate_dirichlet_boundary_data(self) -> np.ndarray: + """ + Generate Dirichlet boundary data. + + This function returns the boundary points and their corresponding values. + + :return: A tuple containing two arrays: + - The first array contains the boundary points as numpy arrays. + - The second array contains the values of the boundary points as numpy arrays. + :rtype: Tuple[np.ndarray, np.ndarray] + """ + x = [] + y = [] + for bound_id, bound_pts in self.boundary_points.items(): + # get the coordinates of the boundary points + for pt in bound_pts: + pt_new = np.array([pt[0], pt[1]], dtype=np.float64) + x.append(pt_new) + val = np.array( + self.bound_function_dict[bound_id](pt[0], pt[1]), dtype=np.float64 + ).reshape(-1, 1) + y.append(val) + + print(f"[INFO] : Total number of Dirichlet boundary points = {len(x)}") + self.total_dirichlet_dofs = len(x) + print(f"[INFO] : Shape of Dirichlet-X = {np.array(x).shape}") + print(f"[INFO] : Shape of Y = {np.array(y).shape}") + + return x, y
+ + +
+[docs] + def generate_dirichlet_boundary_data_vector(self, component) -> np.ndarray: + """ + Generate the boundary data vector for the Dirichlet boundary condition. + + This function returns the boundary points and their corresponding values for a specific component. + + :param component: The component for which the boundary data vector is generated. + :type component: int + + :return: The boundary points and their values as numpy arrays. + :rtype: tuple(numpy.ndarray, numpy.ndarray) + """ + x = [] + y = [] + for bound_id, bound_pts in self.boundary_points.items(): + # get the coordinates of the boundary points + for pt in bound_pts: + pt_new = np.array([pt[0], pt[1]], dtype=np.float64) + x.append(pt_new) + val = np.array( + self.bound_function_dict[bound_id](pt[0], pt[1])[component], dtype=np.float64 + ).reshape(-1, 1) + y.append(val) + + return x, y
+ + +
+[docs] + def get_shape_function_val(self, cell_index) -> np.ndarray: + """ + Get the actual values of the shape functions on a given cell. + + :param cell_index: The index of the cell. + :type cell_index: int + + :return: An array containing the actual values of the shape functions. + :rtype: np.ndarray + + :raises ValueError: If the cell_index is greater than the number of cells. + """ + if cell_index >= len(self.fe_cell) or cell_index < 0: + raise ValueError( + f"cell_index should be less than {self.n_cells} and greater than or equal to 0" + ) + + return self.fe_cell[cell_index].basis_at_quad.copy()
+ + +
+[docs] + def get_shape_function_grad_x(self, cell_index) -> np.ndarray: + """ + Get the gradient of the shape function with respect to the x-coordinate. + + :param cell_index: The index of the cell. + :type cell_index: int + + :return: An array containing the gradient of the shape function with respect to the x-coordinate. + :rtype: np.ndarray + + :raises ValueError: If the cell_index is greater than the number of cells. + + This function returns the actual values of the gradient of the shape function on a given cell. + """ + if cell_index >= len(self.fe_cell) or cell_index < 0: + raise ValueError( + f"cell_index should be less than {self.n_cells} and greater than or equal to 0" + ) + + return self.fe_cell[cell_index].basis_gradx_at_quad.copy()
+ + +
+[docs] + def get_shape_function_grad_x_ref(self, cell_index) -> np.ndarray: + """ + Get the gradient of the shape function with respect to the x-coordinate on the reference element. + + :param cell_index: The index of the cell. + :type cell_index: int + + :return: An array containing the gradient of the shape function with respect to the x-coordinate. + :rtype: np.ndarray + + :raises ValueError: If the cell_index is greater than the number of cells. + """ + if cell_index >= len(self.fe_cell) or cell_index < 0: + raise ValueError( + f"cell_index should be less than {self.n_cells} and greater than or equal to 0" + ) + + return self.fe_cell[cell_index].basis_gradx_at_quad_ref.copy()
+ + +
+[docs] + def get_shape_function_grad_y(self, cell_index) -> np.ndarray: + """ + Get the gradient of the shape function with respect to y at the given cell index. + + :param cell_index: The index of the cell. + :type cell_index: int + + :return: The gradient of the shape function with respect to y. + :rtype: np.ndarray + + :raises ValueError: If the cell_index is greater than the total number of cells. + """ + if cell_index >= len(self.fe_cell) or cell_index < 0: + raise ValueError( + f"cell_index should be less than {self.n_cells} and greater than or equal to 0" + ) + + return self.fe_cell[cell_index].basis_grady_at_quad.copy()
+ + +
+[docs] + def get_shape_function_grad_y_ref(self, cell_index): + """ + Get the gradient of the shape function with respect to y at the reference element. + + :param cell_index: The index of the cell. + :type cell_index: int + :return: The gradient of the shape function with respect to y at the reference element. + :rtype: np.ndarray + :raises ValueError: If cell_index is greater than the number of cells. + + This function returns the gradient of the shape function with respect to y at the reference element + for a given cell. The shape function gradient values are stored in the `basis_grady_at_quad_ref` array + of the corresponding finite element cell. The `cell_index` parameter specifies the index of the cell + for which the shape function gradient is required. If the `cell_index` is greater than the total number + of cells, a `ValueError` is raised. + + .. note:: + The returned gradient values are copied from the `basis_grady_at_quad_ref` array to ensure immutability. + """ + if cell_index >= len(self.fe_cell) or cell_index < 0: + raise ValueError( + f"cell_index should be less than {self.n_cells} and greater than or equal to 0" + ) + + return self.fe_cell[cell_index].basis_grady_at_quad_ref.copy()
+ + +
+[docs] + def get_quadrature_actual_coordinates(self, cell_index) -> np.ndarray: + """ + Get the actual coordinates of the quadrature points for a given cell. + + :param cell_index: The index of the cell. + :type cell_index: int + + :return: An array containing the actual coordinates of the quadrature points. + :rtype: np.ndarray + + :raises ValueError: If the cell_index is greater than the number of cells. + + :example: + >>> fespace = FESpace2D() + >>> fespace.get_quadrature_actual_coordinates(0) + array([[0.1, 0.2], + [0.3, 0.4], + [0.5, 0.6]]) + """ + if cell_index >= len(self.fe_cell) or cell_index < 0: + raise ValueError( + f"cell_index should be less than {self.n_cells} and greater than or equal to 0" + ) + + return self.fe_cell[cell_index].quad_actual_coordinates.copy()
+ + +
+[docs] + def get_quadrature_weights(self, cell_index) -> np.ndarray: + """ + Return the quadrature weights for a given cell. + + Parameters + ---------- + cell_index : int + The index of the cell for which the quadrature weights are needed. + + Returns + ------- + np.ndarray + The quadrature weights for the given cell of dimension (N_Quad_Points, 1). + + Raises + ------ + ValueError + If cell_index is greater than the number of cells. + + Notes + ----- + This function returns the quadrature weights associated with a specific cell. + The quadrature weights are stored in the `mult` attribute of the `fe_cell` object. + + Example + ------- + >>> fespace = FESpace2D() + >>> weights = fespace.get_quadrature_weights(0) + >>> print(weights) + [0.1, 0.2, 0.3, 0.4] + + :param cell_index: The index of the cell for which the quadrature weights are needed. + :type cell_index: int + :return: The quadrature weights for the given cell. + :rtype: np.ndarray + :raises ValueError: If cell_index is greater than the number of cells. + """ + if cell_index >= len(self.fe_cell) or cell_index < 0: + raise ValueError( + f"cell_index should be less than {self.n_cells} and greater than or equal to 0" + ) + + return self.fe_cell[cell_index].mult.copy()
+ + +
+[docs] + def get_forcing_function_values(self, cell_index) -> np.ndarray: + """ + Get the forcing function values at the quadrature points. + + :param cell_index: The index of the cell. + :type cell_index: int + + :return: The forcing function values at the quadrature points. + :rtype: np.ndarray + + :raises ValueError: If cell_index is greater than the number of cells. + + This function computes the forcing function values at the quadrature points for a given cell. + It loops over all the basis functions and computes the integral using the actual coordinates + and the basis functions at the quadrature points. The resulting values are stored in the + `forcing_at_quad` attribute of the corresponding `fe_cell` object. + + Note: The forcing function is evaluated using the `forcing_function` method of the `fe_cell` + object. + + Example usage: + >>> fespace = FESpace2D() + >>> cell_index = 0 + >>> forcing_values = fespace.get_forcing_function_values(cell_index) + """ + if cell_index >= len(self.fe_cell) or cell_index < 0: + raise ValueError( + f"cell_index should be less than {self.n_cells} and greater than or equal to 0" + ) + + # Changed by Thivin: To assemble the forcing function at the quadrature points here in the fespace + # so that it can be used to handle multiple dimensions on a vector valud problem + + # get number of shape functions + n_shape_functions = self.fe_cell[cell_index].basis_function.num_shape_functions + + # Loop over all the basis functions and compute the integral + f_integral = np.zeros((n_shape_functions, 1), dtype=np.float64) + + for i in range(n_shape_functions): + val = 0 + for q in range(self.fe_cell[cell_index].basis_at_quad.shape[1]): + x = self.fe_cell[cell_index].quad_actual_coordinates[q, 0] + y = self.fe_cell[cell_index].quad_actual_coordinates[q, 1] + # print("f_values[q] = ",f_values[q]) + + # the JAcobian and the quadrature weights are pre multiplied to the basis functions + val += (self.fe_cell[cell_index].basis_at_quad[i, q]) * self.fe_cell[ + cell_index + ].forcing_function(x, y) + # print("val = ", val) + + f_integral[i] = val + + self.fe_cell[cell_index].forcing_at_quad = f_integral + + return self.fe_cell[cell_index].forcing_at_quad.copy()
+ + +
+[docs] + def get_forcing_function_values_vector(self, cell_index, component) -> np.ndarray: + """ + This function will return the forcing function values at the quadrature points + based on the Component of the RHS Needed, for vector valued problems + + :param cell_index: The index of the cell + :type cell_index: int + :param component: The component of the RHS needed + :type component: int + :return: The forcing function values at the quadrature points + :rtype: np.ndarray + :raises ValueError: If cell_index is greater than the number of cells + """ + if cell_index >= len(self.fe_cell) or cell_index < 0: + raise ValueError( + f"cell_index should be less than {self.n_cells} and greater than or equal to 0" + ) + + # get the coordinates + x = self.fe_cell[cell_index].quad_actual_coordinates[:, 0] + y = self.fe_cell[cell_index].quad_actual_coordinates[:, 1] + + # compute the forcing function values + f_values = self.fe_cell[cell_index].forcing_function(x, y)[component] + + # compute the integral + f_integral = np.sum(self.fe_cell[cell_index].basis_at_quad * f_values, axis=1) + + self.fe_cell[cell_index].forcing_at_quad = f_integral.reshape(-1, 1) + + return self.fe_cell[cell_index].forcing_at_quad.copy()
+ + +
+[docs] + def get_sensor_data(self, exact_solution, num_points): + """ + Obtain sensor data (actual solution) at random points. + + This method is used in the inverse problem to obtain the sensor data at random points within the domain. + Currently, it only works for problems with an analytical solution. + Methodologies to obtain sensor data for problems from a file are not implemented yet. + It is also not implemented for external or complex meshes. + + :param exact_solution: A function that computes the exact solution at a given point. + :type exact_solution: function + :param num_points: The number of random points to generate. + :type num_points: int + :return: A tuple containing the generated points and the exact solution at those points. + :rtype: tuple(numpy.ndarray, numpy.ndarray) + """ + # generate random points within the bounds of the domain + # get the bounds of the domain + x_min = np.min(self.mesh.points[:, 0]) + x_max = np.max(self.mesh.points[:, 0]) + y_min = np.min(self.mesh.points[:, 1]) + y_max = np.max(self.mesh.points[:, 1]) + # sample n random points within the bounds of the domain + # Generate points in the unit square + + num_internal_points = int(num_points * 0.9) + + points = lhs(2, samples=num_internal_points) + points[:, 0] = x_min + (x_max - x_min) * points[:, 0] + points[:, 1] = y_min + (y_max - y_min) * points[:, 1] + # get the exact solution at the points + exact_sol = exact_solution(points[:, 0], points[:, 1]) + + # print the shape of the points and the exact solution + print(f"[INFO] : Number of sensor points = {points.shape[0]}") + print(f"[INFO] : Shape of sensor points = {points.shape}") + + # plot the points + plt.figure(figsize=(6.4, 4.8), dpi=300) + plt.scatter(points[:, 0], points[:, 1], marker="x", color="r", s=2) + plt.axis("equal") + plt.title("Sensor Points") + plt.tight_layout() + plt.savefig("sensor_points.png", bbox_inches="tight") + + return points, exact_sol
+ + +
+[docs] + def get_sensor_data_external(self, exact_sol, num_points, file_name): + """ + This method is used to obtain the sensor data from an external file. + + :param exact_sol: The exact solution values. + :type exact_sol: array-like + :param num_points: The number of points to sample from the data. + :type num_points: int + :param file_name: The path to the file containing the sensor data. + :type file_name: str + + :return: A tuple containing two arrays: + - points (ndarray): The sampled points from the data. + - exact_sol (ndarray): The corresponding exact solution values. + :rtype: tuple + """ + # use pandas to read the file + df = pd.read_csv(file_name) + + x = df.iloc[:, 0].values + y = df.iloc[:, 1].values + exact_sol = df.iloc[:, 2].values + + # now sample num_points from the data + indices = np.random.randint(0, x.shape[0], num_points) + + x = x[indices] + y = y[indices] + exact_sol = exact_sol[indices] + + # stack them together + points = np.stack((x, y), axis=1) + + return points, exact_sol
+
+ +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/fastvpinns/FE/quad_affine.html b/_modules/fastvpinns/FE/quad_affine.html new file mode 100644 index 0000000..f3b983e --- /dev/null +++ b/_modules/fastvpinns/FE/quad_affine.html @@ -0,0 +1,311 @@ + + + + + + fastvpinns.FE.quad_affine — fastvpinns 1.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for fastvpinns.FE.quad_affine

+"""
+file: quad_affine.py
+description: This file defines the Quad Affine transformation of the reference element.
+             The implementation is referenced from the ParMooN project (File: QuadAffine.C).
+authors: Thivin Anandh D
+changelog: 30/Aug/2023 - Initial version
+known_issues: None
+dependencies: None specified.
+"""
+
+import numpy as np
+from .fe_transformation_2d import FETransforamtion2D
+
+
+
+[docs] +class QuadAffin(FETransforamtion2D): + """ + Defines the Quad Affine transformation of the reference element. + + :param co_ordinates: The coordinates of the reference element. + :type co_ordinates: numpy.ndarray + """ + + def __init__(self, co_ordinates) -> None: + """ + Constructor for the QuadAffin class. + + :param co_ordinates: The coordinates of the reference element. + :type co_ordinates: numpy.ndarray + """ + self.co_ordinates = co_ordinates + self.set_cell() + self.get_jacobian( + 0, 0 + ) # 0,0 is just a dummy value # this sets the jacobian and the inverse of the jacobian + +
+[docs] + def set_cell(self): + """ + Set the cell coordinates, which will be used to calculate the Jacobian and actual values. + + :param None: + There are no parameters for this method. + + :returns None: + This method does not return anything. + """ + + self.x0 = self.co_ordinates[0][0] + self.x1 = self.co_ordinates[1][0] + self.x2 = self.co_ordinates[2][0] + self.x3 = self.co_ordinates[3][0] + + # get the y-coordinates of the cell + self.y0 = self.co_ordinates[0][1] + self.y1 = self.co_ordinates[1][1] + self.y2 = self.co_ordinates[2][1] + self.y3 = self.co_ordinates[3][1] + + self.xc0 = (self.x1 + self.x3) * 0.5 + self.xc1 = (self.x1 - self.x0) * 0.5 + self.xc2 = (self.x3 - self.x0) * 0.5 + + self.yc0 = (self.y1 + self.y3) * 0.5 + self.yc1 = (self.y1 - self.y0) * 0.5 + self.yc2 = (self.y3 - self.y0) * 0.5
+ + +
+[docs] + def get_original_from_ref(self, xi, eta): + """ + Returns the original coordinates from the reference coordinates. + + :param float xi: The xi coordinate. + :param float eta: The eta coordinate. + :return: numpy.ndarray + The original coordinates. + """ + x = self.xc0 + self.xc1 * xi + self.xc2 * eta + y = self.yc0 + self.yc1 * xi + self.yc2 * eta + + return np.array([x, y])
+ + +
+[docs] + def get_jacobian(self, xi, eta): + """ + Returns the Jacobian of the transformation. + + :param xi: The xi coordinate. + :type xi: float + :param eta: The eta coordinate. + :type eta: float + + :return: The Jacobian of the transformation. + :rtype: float + """ + self.detjk = self.xc1 * self.yc2 - self.xc2 * self.yc1 + self.rec_detjk = 1 / self.detjk + + return abs(self.detjk)
+ + +
+[docs] + def get_orig_from_ref_derivative(self, ref_gradx, ref_grady, xi, eta): + """ + Returns the derivatives of the original coordinates with respect to the reference coordinates. + + :param ref_gradx: The reference gradient in the x-direction. + :type ref_gradx: numpy.ndarray + :param ref_grady: The reference gradient in the y-direction. + :type ref_grady: numpy.ndarray + :param xi: The xi coordinate. + :type xi: float + :param eta: The eta coordinate. + :type eta: float + + :return: The derivatives of the original coordinates with respect to the reference coordinates. + :rtype: tuple + """ + gradx_orig = np.zeros(ref_gradx.shape) + grady_orig = np.zeros(ref_grady.shape) + + for i in range(ref_gradx.shape[0]): + gradx_orig[i] = (self.yc2 * ref_gradx[i] - self.yc1 * ref_grady[i]) * self.rec_detjk + grady_orig[i] = (-self.xc2 * ref_gradx[i] + self.xc1 * ref_grady[i]) * self.rec_detjk + + return gradx_orig, grady_orig
+ + +
+[docs] + def get_orig_from_ref_second_derivative(self, grad_xx_ref, grad_xy_ref, grad_yy_ref, xi, eta): + """ + Returns the second derivatives (xx, xy, yy) of the original coordinates with respect to the reference coordinates. + + :param grad_xx_ref: The reference second derivative in the xx-direction. + :type grad_xx_ref: numpy.ndarray + :param grad_xy_ref: The reference second derivative in the xy-direction. + :type grad_xy_ref: numpy.ndarray + :param grad_yy_ref: The reference second derivative in the yy-direction. + :type grad_yy_ref: numpy.ndarray + :param xi: The xi coordinate. + :type xi: float + :param eta: The eta coordinate. + :type eta: float + + :return: The second derivatives (xx, xy, yy) of the original coordinates with respect to the reference coordinates. + :rtype: tuple + """ + GeoData = np.zeros((3, 3)) + Eye = np.identity(3) + + # Populate GeoData (assuming xc1, xc2, yc1, yc2 are defined) + GeoData[0, 0] = self.xc1 * self.xc1 + GeoData[0, 1] = 2 * self.xc1 * self.yc1 + GeoData[0, 2] = self.yc1 * self.yc1 + GeoData[1, 0] = self.xc1 * self.xc2 + GeoData[1, 1] = self.yc1 * self.xc2 + self.xc1 * self.yc2 + GeoData[1, 2] = self.yc1 * self.yc2 + GeoData[2, 0] = self.xc2 * self.xc2 + GeoData[2, 1] = 2 * self.xc2 * self.yc2 + GeoData[2, 2] = self.yc2 * self.yc2 + + # solve the linear system + solution = np.linalg.solve(GeoData, Eye) + + # generate empty arrays for the original second derivatives + grad_xx_orig = np.zeros(grad_xx_ref.shape) + grad_xy_orig = np.zeros(grad_xy_ref.shape) + grad_yy_orig = np.zeros(grad_yy_ref.shape) + + for j in range(grad_xx_ref.shape[0]): + r20 = grad_xx_ref[j] + r11 = grad_xy_ref[j] + r02 = grad_yy_ref[j] + + grad_xx_orig[j] = solution[0, 0] * r20 + solution[0, 1] * r11 + solution[0, 2] * r02 + grad_xy_orig[j] = solution[1, 0] * r20 + solution[1, 1] * r11 + solution[1, 2] * r02 + grad_yy_orig[j] = solution[2, 0] * r20 + solution[2, 1] * r11 + solution[2, 2] * r02 + + return grad_xx_orig, grad_xy_orig, grad_yy_orig
+
+ +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/fastvpinns/FE/quad_bilinear.html b/_modules/fastvpinns/FE/quad_bilinear.html new file mode 100644 index 0000000..e8458d5 --- /dev/null +++ b/_modules/fastvpinns/FE/quad_bilinear.html @@ -0,0 +1,297 @@ + + + + + + fastvpinns.FE.quad_bilinear — fastvpinns 1.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for fastvpinns.FE.quad_bilinear

+"""
+file: quad_bilinear.py
+description: This file defines the Quad Affine transformation of the reference element.
+             The implementation is referenced from the ParMooN project (File: QuadBilineare.C).
+authors: Thivin Anandh D
+changelog: 30/Aug/2023 - Initial version
+known_issues: Second derivative Calculations are not implemented as of now. 
+dependencies: None specified.
+"""
+
+import numpy as np
+from .fe_transformation_2d import FETransforamtion2D
+
+
+
+[docs] +class QuadBilinear(FETransforamtion2D): + """ + Defines the Quad Bilinear transformation of the reference element. + + :param co_ordinates: The coordinates of the reference element. + :type co_ordinates: numpy.ndarray + """ + + def __init__(self, co_ordinates) -> None: + """ + Constructor for the QuadBilinear class. + + :param co_ordinates: The coordinates of the reference element. + :type co_ordinates: numpy.ndarray + """ + self.co_ordinates = co_ordinates + self.set_cell() + self.detjk = None # Jacobian of the transformation + +
+[docs] + def set_cell(self): + """ + Set the cell coordinates, which will be used as intermediate values to calculate the Jacobian and actual values. + + :param None: + :type None: + + :returns: None + :rtype: None + """ + self.x0 = self.co_ordinates[0][0] + self.x1 = self.co_ordinates[1][0] + self.x2 = self.co_ordinates[2][0] + self.x3 = self.co_ordinates[3][0] + + # get the y-coordinates of the cell + self.y0 = self.co_ordinates[0][1] + self.y1 = self.co_ordinates[1][1] + self.y2 = self.co_ordinates[2][1] + self.y3 = self.co_ordinates[3][1] + + self.xc0 = (self.x0 + self.x1 + self.x2 + self.x3) * 0.25 + self.xc1 = (-self.x0 + self.x1 + self.x2 - self.x3) * 0.25 + self.xc2 = (-self.x0 - self.x1 + self.x2 + self.x3) * 0.25 + self.xc3 = (self.x0 - self.x1 + self.x2 - self.x3) * 0.25 + + self.yc0 = (self.y0 + self.y1 + self.y2 + self.y3) * 0.25 + self.yc1 = (-self.y0 + self.y1 + self.y2 - self.y3) * 0.25 + self.yc2 = (-self.y0 - self.y1 + self.y2 + self.y3) * 0.25 + self.yc3 = (self.y0 - self.y1 + self.y2 - self.y3) * 0.25
+ + +
+[docs] + def get_original_from_ref(self, xi, eta): + """ + This method returns the original coordinates from the reference coordinates. + + :param xi: The xi coordinate in the reference element. + :type xi: float + :param eta: The eta coordinate in the reference element. + :type eta: float + + :returns: The original coordinates [x, y] corresponding to the given reference coordinates. + :rtype: numpy.ndarray + """ + x = self.xc0 + self.xc1 * xi + self.xc2 * eta + self.xc3 * xi * eta + y = self.yc0 + self.yc1 * xi + self.yc2 * eta + self.yc3 * xi * eta + + return np.array([x, y], dtype=np.float64)
+ + +
+[docs] + def get_jacobian(self, xi, eta): + """ + This method returns the Jacobian of the transformation. + + :param xi: The xi coordinate in the reference element. + :type xi: float + :param eta: The eta coordinate in the reference element. + :type eta: float + + :returns: The Jacobian of the transformation at the given reference coordinates. + :rtype: float + """ + self.detjk = abs( + (self.xc1 + self.xc3 * eta) * (self.yc2 + self.yc3 * xi) + - (self.xc2 + self.xc3 * xi) * (self.yc1 + self.yc3 * eta) + ) + return self.detjk
+ + +
+[docs] + def get_orig_from_ref_derivative(self, ref_gradx, ref_grady, xi, eta): + """ + This method returns the derivatives of the original coordinates with respect to the reference coordinates. + + :param ref_gradx: The gradient of the xi coordinate in the reference element. + :type ref_gradx: numpy.ndarray + :param ref_grady: The gradient of the eta coordinate in the reference element. + :type ref_grady: numpy.ndarray + :param xi: The xi coordinate in the reference element. + :type xi: float + :param eta: The eta coordinate in the reference element. + :type eta: float + + :returns: The derivatives of the original coordinates [x, y] with respect to the reference coordinates. + :rtype: numpy.ndarray + """ + n_test = ref_gradx.shape[0] + gradx_orig = np.zeros(ref_gradx.shape, dtype=np.float64) + grady_orig = np.zeros(ref_grady.shape, dtype=np.float64) + + for j in range(n_test): + Xi = xi + Eta = eta + rec_detjk = 1 / ( + (self.xc1 + self.xc3 * Eta) * (self.yc2 + self.yc3 * Xi) + - (self.xc2 + self.xc3 * Xi) * (self.yc1 + self.yc3 * Eta) + ) + gradx_orig[j] = ( + (self.yc2 + self.yc3 * Xi) * ref_gradx[j] + - (self.yc1 + self.yc3 * Eta) * ref_grady[j] + ) * rec_detjk + grady_orig[j] = ( + -(self.xc2 + self.xc3 * Xi) * ref_gradx[j] + + (self.xc1 + self.xc3 * Eta) * ref_grady[j] + ) * rec_detjk + + return gradx_orig, grady_orig
+ + +
+[docs] + def get_orig_from_ref_second_derivative(self, grad_xx_ref, grad_xy_ref, grad_yy_ref, xi, eta): + """ + This method returns the second derivatives of the original coordinates with respect to the reference coordinates. + + :param grad_xx_ref: The second derivative of the xi coordinate in the reference element. + :type grad_xx_ref: numpy.ndarray + :param grad_xy_ref: The mixed second derivative of the xi and eta coordinates in the reference element. + :type grad_xy_ref: numpy.ndarray + :param grad_yy_ref: The second derivative of the eta coordinate in the reference element. + :type grad_yy_ref: numpy.ndarray + :param xi: The xi coordinate in the reference element. + :type xi: float + :param eta: The eta coordinate in the reference element. + :type eta: float + + :returns: The second derivatives of the original coordinates [xx, xy, yy] with respect to the reference coordinates. + :rtype: numpy.ndarray + """ + # print(" Error : Second Derivative not implemented -- Ignore this error, if second derivative is not required ") + return grad_xx_ref, grad_xy_ref, grad_yy_ref
+
+ +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/fastvpinns/FE/quadratureformulas.html b/_modules/fastvpinns/FE/quadratureformulas.html new file mode 100644 index 0000000..9c09939 --- /dev/null +++ b/_modules/fastvpinns/FE/quadratureformulas.html @@ -0,0 +1,183 @@ + + + + + + fastvpinns.FE.quadratureformulas — fastvpinns 1.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + + +
  • +
  • +
+
+
+
+
+ +

Source code for fastvpinns.FE.quadratureformulas

+"""
+file: quadratureformulas.py
+description: Abstract class for all quadrature formulas
+authors: Thivin Anandh D
+changelog: Not specified
+known_issues: None
+dependencies: numpy, scipy
+"""
+
+from abc import abstractmethod
+
+
+
+[docs] +class Quadratureformulas: + """ + Defines the Quadrature Formulas for the 2D Quadrilateral elements. + + :param quad_order: The order of the quadrature. + :type quad_order: int + :param quad_type: The type of the quadrature. + :type quad_type: str + """ + + def __init__(self, quad_order: int, quad_type: str, num_quad_points: int): + """ + Constructor for the Quadratureformulas_Quad2D class. + + :param quad_order: The order of the quadrature. + :type quad_order: int + :param quad_type: The type of the quadrature. + :type quad_type: str + """ + self.quad_order = quad_order + self.quad_type = quad_type + self.num_quad_points = num_quad_points + +
+[docs] + @abstractmethod + def get_quad_values(self): + """ + Returns the quadrature weights, xi and eta values. + + :return: A tuple containing the quadrature weights, xi values, and eta values. + :rtype: tuple + """
+ + +
+[docs] + @abstractmethod + def get_num_quad_points(self): + """ + Returns the number of quadrature points. + + :return: The number of quadrature points. + :rtype: int + """
+
+ +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/fastvpinns/FE/quadratureformulas_quad2d.html b/_modules/fastvpinns/FE/quadratureformulas_quad2d.html new file mode 100644 index 0000000..07aefd1 --- /dev/null +++ b/_modules/fastvpinns/FE/quadratureformulas_quad2d.html @@ -0,0 +1,304 @@ + + + + + + fastvpinns.FE.quadratureformulas_quad2d — fastvpinns 1.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + + +
  • +
  • +
+
+
+
+
+ +

Source code for fastvpinns.FE.quadratureformulas_quad2d

+"""
+file: quadratureformulas_quad2d.py
+description: This file defines the Quadrature Formulas for the 2D Quadrilateral elements.
+             It supports both Gauss-Legendre and Gauss-Jacobi quadrature types.
+             The quadrature points and weights are calculated based on the specified quadrature order and type.
+authors: Not specified
+changelog: Not specified
+known_issues: None
+dependencies: numpy, scipy
+"""
+
+import numpy as np
+from scipy.special import roots_legendre, roots_jacobi, jacobi, gamma
+from scipy.special import legendre
+from scipy.special import eval_legendre, legendre
+
+from .quadratureformulas import Quadratureformulas
+
+
+
+[docs] +class Quadratureformulas_Quad2D(Quadratureformulas): + """ + Defines the Quadrature Formulas for the 2D Quadrilateral elements. + + :param quad_order: The order of the quadrature. + :type quad_order: int + :param quad_type: The type of the quadrature. + :type quad_type: str + """ + + def __init__(self, quad_order: int, quad_type: str): + """ + Constructor for the Quadratureformulas_Quad2D class. + + :param quad_order: The order of the quadrature. + :type quad_order: int + :param quad_type: The type of the quadrature. + :type quad_type: str + """ + # initialize the super class + super().__init__( + quad_order=quad_order, quad_type=quad_type, num_quad_points=quad_order * quad_order + ) + + # Calculate the Gauss-Legendre quadrature points and weights for 1D + # nodes_1d, weights_1d = roots_jacobi(self.quad_order, 1, 1) + + quad_type = self.quad_type + + if quad_type == "gauss-legendre": + # Commented out by THIVIN - to Just use legendre quadrature points as it is + # if quad_order == 2: + # nodes_1d = np.array([-1, 1]) + # weights_1d = np.array([1, 1]) + # else: + nodes_1d, weights_1d = np.polynomial.legendre.leggauss(quad_order) # Interior points + # nodes_1d = np.concatenate(([-1, 1], nodes_1d)) + # weights_1d = np.concatenate(([1, 1], weights_1d)) + + # Generate the tensor outer product of the nodes + xi_quad, eta_quad = np.meshgrid(nodes_1d, nodes_1d) + xi_quad = xi_quad.flatten() + eta_quad = eta_quad.flatten() + + # Multiply the weights accordingly for 2D + quad_weights = (weights_1d[:, np.newaxis] * weights_1d).flatten() + + # Assign the values + self.xi_quad = xi_quad + self.eta_quad = eta_quad + self.quad_weights = quad_weights + + elif quad_type == "gauss-jacobi": + + def GaussJacobiWeights(Q: int, a, b): + [X, W] = roots_jacobi(Q, a, b) + return [X, W] + + def jacobi_wrapper(n, a, b, x): + + x = np.array(x, dtype=np.float64) + + return jacobi(n, a, b)(x) + + # Weight coefficients + def GaussLobattoJacobiWeights(Q: int, a, b): + W = [] + X = roots_jacobi(Q - 2, a + 1, b + 1)[0] + if a == 0 and b == 0: + W = 2 / ((Q - 1) * (Q) * (jacobi_wrapper(Q - 1, 0, 0, X) ** 2)) + Wl = 2 / ((Q - 1) * (Q) * (jacobi_wrapper(Q - 1, 0, 0, -1) ** 2)) + Wr = 2 / ((Q - 1) * (Q) * (jacobi_wrapper(Q - 1, 0, 0, 1) ** 2)) + else: + W = ( + 2 ** (a + b + 1) + * gamma(a + Q) + * gamma(b + Q) + / ( + (Q - 1) + * gamma(Q) + * gamma(a + b + Q + 1) + * (jacobi_wrapper(Q - 1, a, b, X) ** 2) + ) + ) + Wl = ( + (b + 1) + * 2 ** (a + b + 1) + * gamma(a + Q) + * gamma(b + Q) + / ( + (Q - 1) + * gamma(Q) + * gamma(a + b + Q + 1) + * (jacobi_wrapper(Q - 1, a, b, -1) ** 2) + ) + ) + Wr = ( + (a + 1) + * 2 ** (a + b + 1) + * gamma(a + Q) + * gamma(b + Q) + / ( + (Q - 1) + * gamma(Q) + * gamma(a + b + Q + 1) + * (jacobi_wrapper(Q - 1, a, b, 1) ** 2) + ) + ) + W = np.append(W, Wr) + W = np.append(Wl, W) + X = np.append(X, 1) + X = np.append(-1, X) + return [X, W] + + # get quadrature points and weights in 1D + x, w = GaussLobattoJacobiWeights(self.quad_order, 0, 0) + + # Generate the tensor outer product of the nodes + xi_quad, eta_quad = np.meshgrid(x, x) + xi_quad = xi_quad.flatten() + eta_quad = eta_quad.flatten() + + # Multiply the weights accordingly for 2D + quad_weights = (w[:, np.newaxis] * w).flatten() + + # Assign the values + self.xi_quad = xi_quad + self.eta_quad = eta_quad + self.quad_weights = quad_weights + + else: + print("Supported quadrature types are: gauss-legendre, gauss-jacobi") + print( + f"Invalid quadrature type {quad_type} in {self.__class__.__name__} from {__name__}." + ) + raise ValueError("Quadrature type not supported.") + +
+[docs] + def get_quad_values(self): + """ + Returns the quadrature weights, xi and eta values. + + :return: A tuple containing the quadrature weights, xi values, and eta values. + :rtype: tuple + """ + return self.quad_weights, self.xi_quad, self.eta_quad
+ + +
+[docs] + def get_num_quad_points(self): + """ + Returns the number of quadrature points. + + :return: The number of quadrature points. + :rtype: int + """ + return self.num_quad_points
+
+ +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/fastvpinns/Geometry/geometry.html b/_modules/fastvpinns/Geometry/geometry.html new file mode 100644 index 0000000..76a4d1c --- /dev/null +++ b/_modules/fastvpinns/Geometry/geometry.html @@ -0,0 +1,208 @@ + + + + + + fastvpinns.Geometry.geometry — fastvpinns 1.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for fastvpinns.Geometry.geometry

+"""
+This module, `geometry.py`, contains the `Geometry` Abstract class which defines functions to read mesh from Gmsh and 
+generate internal mesh for 2D and 3D geometries. 
+
+Author: Thivin Anandh D
+Date: 03-May-2024
+"""
+
+from pathlib import Path
+import numpy as np
+import matplotlib.pyplot as plt
+import matplotlib.colors as mcolors
+import meshio
+from pyDOE import lhs
+
+import gmsh
+
+from abc import abstractmethod
+
+
+
+[docs] +class Geometry: + """ + Abstract class which defines functions to read mesh from Gmsh and internal mesh for 2D problems. + + :param mesh_type: The type of mesh to be used. + :type mesh_type: str + :param mesh_generation_method: The method used to generate the mesh. + :type mesh_generation_method: str + """ + + def __init__(self, mesh_type, mesh_generation_method): + self.mesh_type = mesh_type + self.mesh_generation_method = mesh_generation_method + +
+[docs] + @abstractmethod + def read_mesh( + self, + mesh_file: str, + boundary_point_refinement_level: int, + bd_sampling_method: str, + refinement_level: int, + ): + """ + Abstract method to read mesh from Gmsh. + + :param mesh_file: The path to the mesh file. + :type mesh_file: str + :param boundary_point_refinement_level: The refinement level of the boundary points. + :type boundary_point_refinement_level: int + :param bd_sampling_method: The method used to sample the boundary points. + :type bd_sampling_method: str + :param refinement_level: The refinement level of the mesh. + :type refinement_level: int + """
+ + +
+[docs] + @abstractmethod + def generate_vtk_for_test(self): + """ + Generates a VTK from Mesh file (External) or using gmsh (for Internal). + + :return: None + """
+ + +
+[docs] + @abstractmethod + def get_test_points(self): + """ + This function is used to extract the test points from the given mesh + + Parameters: + None + + Returns: + test_points (numpy.ndarray): The test points for the given domain + """
+
+ +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/fastvpinns/Geometry/geometry_2d.html b/_modules/fastvpinns/Geometry/geometry_2d.html new file mode 100644 index 0000000..ee7e9ad --- /dev/null +++ b/_modules/fastvpinns/Geometry/geometry_2d.html @@ -0,0 +1,703 @@ + + + + + + fastvpinns.Geometry.geometry_2d — fastvpinns 1.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + + +
  • +
  • +
+
+
+
+
+ +

Source code for fastvpinns.Geometry.geometry_2d

+"""
+This module, `geometry_2d.py`, contains the `Geometry_2D` class which defines functions to read mesh from Gmsh and 
+generate internal mesh for 2D problems. It supports different types of meshes and mesh generation methods. 
+The class also allows for specifying the number of test points in the x and y directions, and the output folder for storing results.
+
+Author: Thivin Anandh D
+Date: 21-Sep-2023
+"""
+
+from pathlib import Path
+import numpy as np
+import matplotlib.pyplot as plt
+import matplotlib.colors as mcolors
+import meshio
+from pyDOE import lhs
+
+import gmsh
+
+from .geometry import Geometry
+
+
+
+[docs] +class Geometry_2D(Geometry): + """ + Defines functions to read mesh from Gmsh and internal mesh for 2D problems. + + :param mesh_type: The type of mesh to be used. + :type mesh_type: str + :param mesh_generation_method: The method used to generate the mesh. + :type mesh_generation_method: str + :param n_test_points_x: The number of test points in the x-direction. + :type n_test_points_x: int + :param n_test_points_y: The number of test points in the y-direction. + :type n_test_points_y: int + :param output_folder: The path to the output folder. + :type output_folder: str + """ + + def __init__( + self, + mesh_type: str, + mesh_generation_method: str, + n_test_points_x: int, + n_test_points_y: int, + output_folder: str, + ): + """ + Constructor for Geometry_2D class. + :param mesh_type: The type of mesh to be used. + :type mesh_type: str + :param mesh_generation_method: The method used to generate the mesh. + :type mesh_generation_method: str + :param n_test_points_x: The number of test points in the x-direction. + :type n_test_points_x: int + :param n_test_points_y: The number of test points in the y-direction. + :type n_test_points_y: int + :param output_folder: The path to the output folder. + :type output_folder: str + """ + # Call the super class constructor + super().__init__(mesh_type, mesh_generation_method) + self.mesh_type = mesh_type + self.mesh_generation_method = mesh_generation_method + self.n_test_points_x = n_test_points_x + self.n_test_points_y = n_test_points_y + self.output_folder = output_folder + + if self.mesh_generation_method not in ["internal", "external"]: + print( + f"Invalid mesh generation method {self.mesh_generation_method} in {self.__class__.__name__} from {__name__}." + ) + raise ValueError("Mesh generation method should be either internal or external.") + + if self.mesh_type not in ["quadrilateral"]: + print( + f"Invalid mesh type {self.mesh_type} in {self.__class__.__name__} from {__name__}." + ) + raise ValueError("Mesh type should be quadrilateral only.") + + # To be filled - only when mesh is internal + self.n_cells_x = None + self.n_cells_y = None + self.x_limits = None + self.y_limits = None + + # to be filled by external + self.mesh_file_name = None + self.mesh = None + self.bd_dict = None + self.cell_points = None + self.test_points = None + +
+[docs] + def read_mesh( + self, + mesh_file: str, + boundary_point_refinement_level: int, + bd_sampling_method: str, + refinement_level: int, + ): + """ + Reads mesh from a Gmsh .msh file and extracts cell information. + + :param mesh_file: The path to the mesh file. + :type mesh_file: str + :param boundary_point_refinement_level: The number of boundary points to be generated. + :type boundary_point_refinement_level: int + :param bd_sampling_method: The method used to generate the boundary points. + :type bd_sampling_method: str + :param refinement_level: The number of times the mesh should be refined. + :type refinement_level: int + :return: The cell points and the dictionary of boundary points. + :rtype: tuple + """ + + self.mesh_file_name = mesh_file + + # bd_sampling_method = "uniform" # "uniform" or "lhs" + + file_extension = Path(mesh_file).suffix + + if file_extension != ".mesh": + raise ValueError("Mesh file should be in .mesh format.") + + # Read mesh using meshio + self.mesh = meshio.read(mesh_file) + + if self.mesh_type == "quadrilateral": + # Extract cell information + cells = self.mesh.cells_dict["quad"] + + num_cells = cells.shape[0] + print(f"[INFO] : Number of cells = {num_cells}") + cell_points = self.mesh.points[cells][ + :, :, 0:2 + ] # remove the z coordinate, which is 0 for all points + + # loop over all cells and rearrange the points in anticlockwise direction + for i in range(num_cells): + cell = cell_points[i] + # get the centroid of the cell + centroid = np.mean(cell, axis=0) + # get the angle of each point with respect to the centroid + angles = np.arctan2(cell[:, 1] - centroid[1], cell[:, 0] - centroid[0]) + # sort the points based on the angles + cell_points[i] = cell[np.argsort(angles)] + + # Extract number of points within each cell + print(f"[INFO] : Number of points per cell = {cell_points.shape}") + + # Collect the Boundary point id's within the domain + boundary_edges = self.mesh.cells_dict["line"] + + # Using the point id, collect the coordinates of the boundary points + boundary_coordinates = self.mesh.points[boundary_edges] + + # Number of Existing Boundary points + print( + f"[INFO] : Number of Bound points before refinement = {np.unique(boundary_coordinates.reshape(-1,3)).shape[0] * 0.5 + 1}" + ) + + # now Get the physical tag of the boundary edges + boundary_tags = self.mesh.cell_data["medit:ref"][0] + + # Generate a Dictionary of boundary tags and boundary coordinates + # Keys will be the boundary tags and values will be the list of coordinates + boundary_dict = {} + + # refine the boundary points based on the number of boundary points needed + for i in range(boundary_coordinates.shape[0]): + p1 = boundary_coordinates[i, 0, :] + p2 = boundary_coordinates[i, 1, :] + + if bd_sampling_method == "uniform": + # take the current point and next point and then perform a uniform sampling + new_points = np.linspace(p1, p2, pow(2, boundary_point_refinement_level) + 1) + elif bd_sampling_method == "lhs": + # take the current point and next point and then perform a uniform sampling + new_points = lhs(2, pow(2, boundary_point_refinement_level) + 1) + new_points[:, 0] = new_points[:, 0] * (p2[0] - p1[0]) + p1[0] + new_points[:, 1] = new_points[:, 1] * (p2[1] - p1[1]) + p1[1] + else: + print( + f"Invalid sampling method {bd_sampling_method} in {self.__class__.__name__} from {__name__}." + ) + raise ValueError("Sampling method should be either uniform or lhs.") + + # get the boundary tag + tag = boundary_tags[i] + + if tag not in boundary_dict: + boundary_dict[tag] = new_points + else: + current_val = new_points + prev_val = boundary_dict[tag] + final = np.vstack([prev_val, current_val]) + boundary_dict[tag] = final + + # get unique + for tag in boundary_dict.keys(): + val = boundary_dict[tag] + val = np.unique(val, axis=0) + boundary_dict[tag] = val + + self.bd_dict = boundary_dict + # print the new boundary points on each boundary tag (key) in a tabular format + + total_bound_points = 0 + print(f"| {'Boundary ID':<12} | {'Number of Points':<16} |") + print(f"| {'-'*12:<12}---{'-'*16:<16} |") + for k, v in self.bd_dict.items(): + print(f"| {k:<12} | {v.shape[0]:<16} |") + total_bound_points += v.shape[0] + + print(f"[INFO] : No of bound pts after refinement: {total_bound_points}") + + # Assign to class values + self.cell_points = cell_points + + # generate testvtk + self.generate_vtk_for_test() + + return cell_points, self.bd_dict
+ + +
+[docs] + def generate_quad_mesh_internal( + self, + x_limits: tuple, + y_limits: tuple, + n_cells_x: int, + n_cells_y: int, + num_boundary_points: int, + ): + """ + Generate and save a quadrilateral mesh with physical curves. + + :param x_limits: The lower and upper limits in the x-direction (x_min, x_max). + :type x_limits: tuple + :param y_limits: The lower and upper limits in the y-direction (y_min, y_max). + :type y_limits: tuple + :param n_cells_x: The number of cells in the x-direction. + :type n_cells_x: int + :param n_cells_y: The number of cells in the y-direction. + :type n_cells_y: int + :param num_boundary_points: The number of boundary points. + :type num_boundary_points: int + :return: The cell points and the dictionary of boundary points. + :rtype: tuple[numpy.ndarray, dict] + """ + + self.n_cells_x = n_cells_x + self.n_cells_y = n_cells_y + self.x_limits = x_limits + self.y_limits = y_limits + + # generate linspace of points in x and y direction + x = np.linspace(x_limits[0], x_limits[1], n_cells_x + 1) + y = np.linspace(y_limits[0], y_limits[1], n_cells_y + 1) + + # Generate quad cells from the points + # the output should be a list of 4 points for each cell , each being a list of 2 points [x,y] + cells = [] + + for i in range(n_cells_x): + for j in range(n_cells_y): + # get the four points of the cell + p1 = [x[i], y[j]] + p2 = [x[i + 1], y[j]] + p3 = [x[i + 1], y[j + 1]] + p4 = [x[i], y[j + 1]] + + # append the points to the cells + cells.append([p1, p2, p3, p4]) + + # convert to numpy array + cells = np.array(cells, dtype=np.float64) + + # use arctan2 to sort the points in anticlockwise direction + # loop over all cells and rearrange the points in anticlockwise direction + for i in range(cells.shape[0]): + cell = cells[i] + # get the centroid of the cell + centroid = np.mean(cell, axis=0) + # get the angle of each point with respect to the centroid + angles = np.arctan2(cell[:, 1] - centroid[1], cell[:, 0] - centroid[0]) + # sort the points based on the angles + cells[i] = cell[np.argsort(angles)] + + # generate a meshio mesh object using the cells + self.mesh = meshio.Mesh(points=cells.reshape(-1, 2), cells=[("quad", cells.reshape(-1, 4))]) + + # lets generate the boundary points, this function will return a dictionary of boundary points + # the keys will be the boundary tags and values will be the list of boundary points + bd_points = {} + + num_bound_per_side = int(num_boundary_points / 4) + + def _temp_bd_func(start, end, num_pts): + """ + This function returns the boundary points between the start and end points + using lhs sampling. + + :param start: The starting point of the boundary. + :type start: float + :param end: The ending point of the boundary. + :type end: float + :param num_pts: The number of points to generate. + :type num_pts: int + :return: The boundary points as a 1D numpy array. + :rtype: numpy.ndarray + """ + # generate the boundary points using lhs as a np.float64 array + bd_pts = lhs(1, num_pts).astype(np.float64) + # scale the points + bd_pts = bd_pts * (end - start) + start + + return bd_pts.reshape(-1) + + # bottom boundary + y_bottom = (np.ones(num_bound_per_side, dtype=np.float64) * y_limits[0]).reshape(-1) + x_bottom = _temp_bd_func(x_limits[0], x_limits[1], num_bound_per_side) + bd_points[1000] = np.vstack([x_bottom, y_bottom]).T + + # right boundary + x_right = (np.ones(num_bound_per_side, dtype=np.float64) * x_limits[1]).reshape(-1) + y_right = _temp_bd_func(y_limits[0], y_limits[1], num_bound_per_side) + bd_points[1001] = np.vstack([x_right, y_right]).T + + # top boundary + y_top = (np.ones(num_bound_per_side, dtype=np.float64) * y_limits[1]).reshape(-1) + x_top = _temp_bd_func(x_limits[0], x_limits[1], num_bound_per_side) + bd_points[1002] = np.vstack([x_top, y_top]).T + + # left boundary + x_left = (np.ones(num_bound_per_side, dtype=np.float64) * x_limits[0]).reshape(-1) + y_left = _temp_bd_func(y_limits[0], y_limits[1], num_bound_per_side) + bd_points[1003] = np.vstack([x_left, y_left]).T + + self.cell_points = cells + self.bd_dict = bd_points + + # generate vtk + self.generate_vtk_for_test() + + return self.cell_points, self.bd_dict
+ + +
+[docs] + def generate_vtk_for_test(self): + """ + Generates a VTK from Mesh file (External) or using gmsh (for Internal). + + :return: None + """ + + if self.mesh_generation_method == "internal": + # initialise the mesh + gmsh.initialize() + + # Now, lets generate the mesh with the points. + x_range = self.x_limits[1] - self.x_limits[0] + y_range = self.y_limits[1] - self.y_limits[0] + + mesh_size_x = x_range / self.n_test_points_x + mesh_size_y = y_range / self.n_test_points_y + + # generate a gmsh with the given parameters + Xmin = self.x_limits[0] + Xmax = self.x_limits[1] + Ymin = self.y_limits[0] + Ymax = self.y_limits[1] + + point1 = gmsh.model.geo.add_point(Xmin, Ymin, 0, mesh_size_x) + point2 = gmsh.model.geo.add_point(Xmax, Ymin, 0, mesh_size_x) + point3 = gmsh.model.geo.add_point(Xmax, Ymax, 0, mesh_size_y) + point4 = gmsh.model.geo.add_point(Xmin, Ymax, 0, mesh_size_y) + + line1 = gmsh.model.geo.add_line(point1, point2, 1000) ## Bottom + line2 = gmsh.model.geo.add_line(point2, point3, 1001) ## Right + line3 = gmsh.model.geo.add_line(point3, point4, 1002) ## Top + line4 = gmsh.model.geo.add_line(point4, point1, 1003) ## Left + + face1 = gmsh.model.geo.add_curve_loop([line1, line2, line3, line4]) + + gmsh.model.geo.add_plane_surface([face1]) + + # Create the relevant Gmsh data structures + # from Gmsh model. + gmsh.model.geo.synchronize() + + # Generate mesh: + gmsh.model.mesh.generate() + + mesh_file_name = Path(self.output_folder) / "internal.msh" + vtk_file_name = Path(self.output_folder) / "internal.vtk" + + gmsh.write(str(mesh_file_name)) + print("[INFO] : Internal mesh file generated at ", str(mesh_file_name)) + + # close the gmsh + gmsh.finalize() + + # read the mesh using meshio + mesh = meshio.gmsh.read(str(mesh_file_name)) + meshio.vtk.write(str(vtk_file_name), mesh, binary=False, fmt_version="4.2") + + print("[INFO] : VTK file for internal mesh file generated at ", str(mesh_file_name)) + + elif self.mesh_generation_method == "external": + + vtk_file_name = Path(self.output_folder) / "external.vtk" + + # Use the internal mesh to generate the vtk file + mesh = meshio.read(str(self.mesh_file_name)) + meshio.vtk.write(str(vtk_file_name), mesh, binary=False, fmt_version="4.2") + + print("[INFO] : VTK file for external mesh file generated at ", str(vtk_file_name))
+ + +
+[docs] + def get_test_points(self): + """ + This function is used to extract the test points from the given mesh + + Parameters: + None + + Returns: + test_points (numpy.ndarray): The test points for the given domain + """ + + if self.mesh_generation_method == "internal": + # vtk_file_name = Path(self.output_folder) / "internal.vtk" + # code over written to plot from np.linspace instead of vtk file + # generate linspace of points in x and y direction based on x and y limits + x = np.linspace(self.x_limits[0], self.x_limits[1], self.n_test_points_x) + y = np.linspace(self.y_limits[0], self.y_limits[1], self.n_test_points_y) + # generate meshgrid + x_grid, y_grid = np.meshgrid(x, y) + # stack the points + self.test_points = np.vstack([x_grid.flatten(), y_grid.flatten()]).T + + return self.test_points + + elif self.mesh_generation_method == "external": + vtk_file_name = Path(self.output_folder) / "external.vtk" + + mesh = meshio.read(str(vtk_file_name)) + points = mesh.points + return points[:, 0:2] # return only first two columns
+ + +
+[docs] + def write_vtk(self, solution, output_path, filename, data_names): + """ + Writes the data to a VTK file. + + :param solution: The solution vector. + :type solution: numpy.ndarray + :param output_path: The path to the output folder. + :type output_path: str + :param filename: The name of the output file. + :type filename: str + :param data_names: The list of data names in the VTK file to be written as scalars. + :type data_names: list + :return: None + """ + # read the existing vtk into file + if self.mesh_generation_method == "internal": + vtk_file_name = Path(self.output_folder) / "internal.vtk" + elif self.mesh_generation_method == "external": + vtk_file_name = Path(self.output_folder) / "external.vtk" + + data = [] + with open(vtk_file_name, "r", encoding="utf-8") as File: + for line in File: + data.append(line) + + # get the output file name + output_file_name = Path(output_path) / filename + + if solution.shape[1] != len(data_names): + print("[Error] : File : geometry_2d.py, Function: write_vtk") + print( + "Num Columns in solution = ", + solution.shape[1], + " Num of data names = ", + len(data_names), + ) + raise ValueError("Number of data names and solution columns are not equal") + + # write the data to the output file + with open(str(output_file_name), "w", encoding="utf-8") as FN: + for line in data: + FN.write(line) + if "POINT_DATA" in line.strip(): + break + + for i in range(solution.shape[1]): + FN.write("SCALARS " + data_names[i] + " float\n") + FN.write("LOOKUP_TABLE default\n") + np.savetxt(FN, solution[:, i]) + FN.write("\n")
+ + + # save the vtk file as image + # self.save_vtk_as_image(str(output_file_name), data_names) + +
+[docs] + def plot_adaptive_mesh( + self, cells_list, area_averaged_cell_loss_list, epoch, filename="cell_residual" + ): + """ + Plots the residuals in each cell of the mesh. + + :param cells_list: The list of cells. + :type cells_list: list + :param area_averaged_cell_loss_list: The list of area averaged cell residual (or the normal residual). + :type area_averaged_cell_loss_list: list + :param epoch: The epoch number (for file name). + :type epoch: int + :param filename: The name of the output file, defaults to "cell_residual". + :type filename: str, optional + :return: None + """ + + plt.figure(figsize=(6.4, 4.8), dpi=300) + + # normalise colors + norm = mcolors.Normalize( + vmin=np.min(area_averaged_cell_loss_list), vmax=np.max(area_averaged_cell_loss_list) + ) + + # Create a colormap + colormap = plt.cm.jet + + for index, cell in enumerate(cells_list): + x = cell[:, 0] + y = cell[:, 1] + + x = np.append(x, x[0]) + y = np.append(y, y[0]) + + curr_cell_loss = float(area_averaged_cell_loss_list[index]) + + color = colormap(norm(curr_cell_loss)) + + plt.fill(x, y, color=color, alpha=0.9) + + plt.plot(x, y, "k") + + # # compute x_min, x_max, y_min, y_max + # x_min = np.min(x) + # x_max = np.max(x) + # y_min = np.min(y) + # y_max = np.max(y) + + # # compute centroid of the cells + # centroid = np.array([np.mean(x), np.mean(y)]) + + # plot the loss text within the cell + # plt.text(centroid[0], centroid[1], f"{curr_cell_loss:.3e}", fontsize=16, horizontalalignment='center', verticalalignment='center') + + sm = plt.cm.ScalarMappable(cmap=colormap, norm=norm) + sm.set_array([]) + plt.colorbar(sm) + + # output filename + output_filename = Path(f"{self.output_folder}/{filename}_{epoch}.png") + plt.title(f"Cell Residual") + plt.savefig(str(output_filename), dpi=300)
+
+ +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/fastvpinns/data/datahandler.html b/_modules/fastvpinns/data/datahandler.html new file mode 100644 index 0000000..62be03e --- /dev/null +++ b/_modules/fastvpinns/data/datahandler.html @@ -0,0 +1,253 @@ + + + + + + fastvpinns.data.datahandler — fastvpinns 1.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for fastvpinns.data.datahandler

+# Abstract class for Datahandler
+# @Author : Thivin Anandh D
+# @Date : 03/May/2024
+# @History : 03/May/2024 - Initial implementation with basic data handling
+
+from abc import abstractmethod
+
+
+
+[docs] +class DataHandler: + """ + This class is to handle data for 2D problems, convert them into tensors using custom tf functions. + It is responsible for all type conversions and data handling. + + .. note:: All inputs to these functions are generally numpy arrays with dtype np.float64. + So we can either maintain the same dtype or convert them to tf.float32 ( for faster computation ). + + :param fespace: The FESpace2D object. + :type fespace: FESpace2D + :param domain: The Domain2D object. + :type domain: Domain2D + :param shape_val_mat_list: List of shape function values for each cell. + :type shape_val_mat_list: list + :param grad_x_mat_list: List of shape function derivatives with respect to x for each cell. + :type grad_x_mat_list: list + :param grad_y_mat_list: List of shape function derivatives with respect to y for each cell. + :type grad_y_mat_list: list + :param x_pde_list: List of actual coordinates of the quadrature points for each cell. + :type x_pde_list: list + :param forcing_function_list: List of forcing function values for each cell. + :type forcing_function_list: list + :param dtype: The tensorflow dtype to be used for all the tensors. + :type dtype: tf.DType + """ + + def __init__(self, fespace, domain, dtype): + """ + Constructor for the DataHandler class + + :param fespace: The FESpace2D object. + :type fespace: FESpace2D + :param domain: The Domain object. + :type domain: Domain2D + :param dtype: The tensorflow dtype to be used for all the tensors. + :type dtype: tf.DType + """ + + self.fespace = fespace + self.domain = domain + self.dtype = dtype + +
+[docs] + @abstractmethod + def get_dirichlet_input(self): + """ + This function will return the input for the Dirichlet boundary data + + :return: + - input_dirichlet (tf.Tensor): The input for the Dirichlet boundary data + - actual_dirichlet (tf.Tensor): The actual Dirichlet boundary data + """
+ + +
+[docs] + @abstractmethod + def get_test_points(self): + """ + Get the test points for the given domain. + + :return: The test points for the given domain. + :rtype: tf.Tensor + """
+ + +
+[docs] + @abstractmethod + def get_bilinear_params_dict_as_tensors(self, function): + """ + Accepts a function from example file and converts all the values into tensors of the given dtype + + Parameters: + - function (function): The function from the example file which returns the bilinear parameters dictionary + + Returns: + - bilinear_params_dict (dict): The bilinear parameters dictionary with all the values converted to tensors + + :param function: The function from the example file which returns the bilinear parameters dictionary + :type function: function + :return: The bilinear parameters dictionary with all the values converted to tensors + :rtype: dict + """
+ + +
+[docs] + @abstractmethod + def get_sensor_data(self, exact_sol, num_sensor_points, mesh_type, file_name=None): + """ + Accepts a function from example file and converts all the values into tensors of the given dtype + + :param exact_sol: The function from the example file which returns the exact solution + :type exact_sol: function + :param num_sensor_points: The number of sensor points to be generated + :type num_sensor_points: int + :param mesh_type: The type of mesh to be used for sensor data generation + :type mesh_type: str + :param file_name: The name of the file to be used for external mesh generation, defaults to None + :type file_name: str, optional + :return: The sensor points and sensor values as tensors + :rtype: tuple[tf.Tensor, tf.Tensor] + """
+ + +
+[docs] + @abstractmethod + def get_inverse_params(self, inverse_params_dict_function): + """ + Accepts a function from example file and converts all the values into tensors of the given dtype + + :param inverse_params_dict_function: The function from the example file which returns the inverse parameters dictionary + :type inverse_params_dict_function: function + :return: The inverse parameters dictionary with all the values converted to tensors + :rtype: dict + """
+
+ +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/fastvpinns/data/datahandler2d.html b/_modules/fastvpinns/data/datahandler2d.html new file mode 100644 index 0000000..90c9cda --- /dev/null +++ b/_modules/fastvpinns/data/datahandler2d.html @@ -0,0 +1,352 @@ + + + + + + fastvpinns.data.datahandler2d — fastvpinns 1.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + + +
  • +
  • +
+
+
+
+
+ +

Source code for fastvpinns.data.datahandler2d

+# This class is to handle data for 2D problems, convert them into tensors using custom tf functions
+# and make them available for the model to train
+# @Author : Thivin Anandh D
+# @Date : 22/Sep/2023
+# @History : 22/Sep/2023 - Initial implementation with basic data handling
+
+from ..FE.fespace2d import *
+from ..Geometry.geometry_2d import *
+import tensorflow as tf
+
+from .datahandler import DataHandler
+
+
+
+[docs] +class DataHandler2D(DataHandler): + """ + This class is to handle data for 2D problems, convert them into tensors using custom tf functions. + It is responsible for all type conversions and data handling. + + .. note:: All inputs to these functions are generally numpy arrays with dtype np.float64. + So we can either maintain the same dtype or convert them to tf.float32 ( for faster computation ). + + :param fespace: The FESpace2D object. + :type fespace: FESpace2D + :param domain: The Domain2D object. + :type domain: Domain2D + :param shape_val_mat_list: List of shape function values for each cell. + :type shape_val_mat_list: list + :param grad_x_mat_list: List of shape function derivatives with respect to x for each cell. + :type grad_x_mat_list: list + :param grad_y_mat_list: List of shape function derivatives with respect to y for each cell. + :type grad_y_mat_list: list + :param x_pde_list: List of actual coordinates of the quadrature points for each cell. + :type x_pde_list: list + :param forcing_function_list: List of forcing function values for each cell. + :type forcing_function_list: list + :param dtype: The tensorflow dtype to be used for all the tensors. + :type dtype: tf.DType + """ + + def __init__(self, fespace, domain, dtype): + """ + Constructor for the DataHandler2D class + + :param fespace: The FESpace2D object. + :type fespace: FESpace2D + :param domain: The Domain2D object. + :type domain: Domain2D + :param shape_val_mat_list: List of shape function values for each cell. + :type shape_val_mat_list: list + :param grad_x_mat_list: List of shape function derivatives with respect to x for each cell. + :type grad_x_mat_list: list + :param grad_y_mat_list: List of shape function derivatives with respect to y for each cell. + :type grad_y_mat_list: list + :param x_pde_list: List of actual coordinates of the quadrature points for each cell. + :type x_pde_list: list + :param forcing_function_list: List of forcing function values for each cell. + :type forcing_function_list: list + :param dtype: The tensorflow dtype to be used for all the tensors. + :type dtype: tf.DType + """ + # call the parent class constructor + super().__init__(fespace=fespace, domain=domain, dtype=dtype) + + self.shape_val_mat_list = [] + self.grad_x_mat_list = [] + self.grad_y_mat_list = [] + self.x_pde_list = [] + self.forcing_function_list = [] + + # check if the given dtype is a valid tensorflow dtype + if not isinstance(self.dtype, tf.DType): + raise TypeError("The given dtype is not a valid tensorflow dtype") + + for cell_index in range(self.fespace.n_cells): + shape_val_mat = tf.constant( + self.fespace.get_shape_function_val(cell_index), dtype=self.dtype + ) + grad_x_mat = tf.constant( + self.fespace.get_shape_function_grad_x(cell_index), dtype=self.dtype + ) + grad_y_mat = tf.constant( + self.fespace.get_shape_function_grad_y(cell_index), dtype=self.dtype + ) + x_pde = tf.constant( + self.fespace.get_quadrature_actual_coordinates(cell_index), dtype=self.dtype + ) + forcing_function = tf.constant( + self.fespace.get_forcing_function_values(cell_index), dtype=self.dtype + ) + self.shape_val_mat_list.append(shape_val_mat) + self.grad_x_mat_list.append(grad_x_mat) + self.grad_y_mat_list.append(grad_y_mat) + self.x_pde_list.append(x_pde) + self.forcing_function_list.append(forcing_function) + + # now convert all the shapes into 3D tensors for easy multiplication + # input tensor - x_pde_list + self.x_pde_list = tf.reshape(self.x_pde_list, [-1, 2]) + + self.forcing_function_list = tf.concat(self.forcing_function_list, axis=1) + + self.shape_val_mat_list = tf.stack(self.shape_val_mat_list, axis=0) + self.grad_x_mat_list = tf.stack(self.grad_x_mat_list, axis=0) + self.grad_y_mat_list = tf.stack(self.grad_y_mat_list, axis=0) + + # test points + self.test_points = None + +
+[docs] + def get_dirichlet_input(self): + """ + This function will return the input for the Dirichlet boundary data + + :return: + - input_dirichlet (tf.Tensor): The input for the Dirichlet boundary data + - actual_dirichlet (tf.Tensor): The actual Dirichlet boundary data + """ + input_dirichlet, actual_dirichlet = self.fespace.generate_dirichlet_boundary_data() + + # convert to tensors + input_dirichlet = tf.constant(input_dirichlet, dtype=self.dtype) + actual_dirichlet = tf.constant(actual_dirichlet, dtype=self.dtype) + actual_dirichlet = tf.reshape(actual_dirichlet, [-1, 1]) + + return input_dirichlet, actual_dirichlet
+ + +
+[docs] + def get_test_points(self): + """ + Get the test points for the given domain. + + :return: The test points for the given domain. + :rtype: tf.Tensor + """ + self.test_points = self.domain.get_test_points() + self.test_points = tf.constant(self.test_points, dtype=self.dtype) + return self.test_points
+ + +
+[docs] + def get_bilinear_params_dict_as_tensors(self, function): + """ + Accepts a function from example file and converts all the values into tensors of the given dtype + + Parameters: + - function (function): The function from the example file which returns the bilinear parameters dictionary + + Returns: + - bilinear_params_dict (dict): The bilinear parameters dictionary with all the values converted to tensors + + :param function: The function from the example file which returns the bilinear parameters dictionary + :type function: function + :return: The bilinear parameters dictionary with all the values converted to tensors + :rtype: dict + """ + # get the dictionary of bilinear parameters + bilinear_params_dict = function() + + # loop over all keys and convert the values to tensors + for key in bilinear_params_dict.keys(): + bilinear_params_dict[key] = tf.constant(bilinear_params_dict[key], dtype=self.dtype) + + return bilinear_params_dict
+ + + # to be used only in inverse problems +
+[docs] + def get_sensor_data(self, exact_sol, num_sensor_points, mesh_type, file_name=None): + """ + Accepts a function from example file and converts all the values into tensors of the given dtype + + :param exact_sol: The function from the example file which returns the exact solution + :type exact_sol: function + :param num_sensor_points: The number of sensor points to be generated + :type num_sensor_points: int + :param mesh_type: The type of mesh to be used for sensor data generation + :type mesh_type: str + :param file_name: The name of the file to be used for external mesh generation, defaults to None + :type file_name: str, optional + :return: The sensor points and sensor values as tensors + :rtype: tuple[tf.Tensor, tf.Tensor] + """ + print(f"mesh_type = {mesh_type}") + if mesh_type == "internal": + # Call the method to get the sensor data + points, sensor_values = self.fespace.get_sensor_data(exact_sol, num_sensor_points) + elif mesh_type == "external": + # Call the method to get the sensor data + points, sensor_values = self.fespace.get_sensor_data_external( + exact_sol, num_sensor_points, file_name + ) + # convert the points and sensor values into tensors + points = tf.constant(points, dtype=self.dtype) + sensor_values = tf.constant(sensor_values, dtype=self.dtype) + + sensor_values = tf.reshape(sensor_values, [-1, 1]) + points = tf.reshape(points, [-1, 2]) + + return points, sensor_values
+ + + # get inverse param dict as tensors +
+[docs] + def get_inverse_params(self, inverse_params_dict_function): + """ + Accepts a function from example file and converts all the values into tensors of the given dtype + + :param inverse_params_dict_function: The function from the example file which returns the inverse parameters dictionary + :type inverse_params_dict_function: function + :return: The inverse parameters dictionary with all the values converted to tensors + :rtype: dict + """ + # loop over all keys and convert the values to tensors + + inverse_params_dict = inverse_params_dict_function() + + for key in inverse_params_dict.keys(): + inverse_params_dict[key] = tf.constant(inverse_params_dict[key], dtype=self.dtype) + + return inverse_params_dict
+
+ +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/fastvpinns/model/model.html b/_modules/fastvpinns/model/model.html new file mode 100644 index 0000000..9f8d25b --- /dev/null +++ b/_modules/fastvpinns/model/model.html @@ -0,0 +1,438 @@ + + + + + + fastvpinns.model.model — fastvpinns 1.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for fastvpinns.model.model

+"""
+file: model.py
+description: This file hosts the Neural Network (NN) model and the training loop for variational Physics-Informed Neural Networks (PINNs).
+             The focus is on the model architecture and the training loop, and not on the loss functions.
+authors: Thivin Anandh D
+changelog: 22/Sep/2023 - Initial implementation with basic model architecture and training loop
+known_issues: None
+dependencies: None specified.
+"""
+
+import tensorflow as tf
+from tensorflow.keras import layers
+from tensorflow.keras import initializers
+import copy
+
+
+# Custom Model
+
+[docs] +class DenseModel(tf.keras.Model): + """ + Defines the Dense Model for the Neural Network for solving Variational PINNs. + + :param layer_dims: List of dimensions of the dense layers. + :type layer_dims: list + :param learning_rate_dict: The dictionary containing the learning rate parameters. + :type learning_rate_dict: dict + :param params_dict: The dictionary containing the parameters. + :type params_dict: dict + :param loss_function: The loss function for the PDE. + :type loss_function: function + :param input_tensors_list: The list containing the input tensors. + :type input_tensors_list: list + :param orig_factor_matrices: The list containing the original factor matrices. + :type orig_factor_matrices: list + :param force_function_list: The force function matrix. + :type force_function_list: tf.Tensor + :param tensor_dtype: The tensorflow dtype to be used for all the tensors. + :type tensor_dtype: tf.DType + :param use_attention: Flag to use attention layer after input, defaults to False. + :type use_attention: bool, optional + :param activation: The activation function to be used for the dense layers, defaults to "tanh". + :type activation: str, optional + :param hessian: Flag to use hessian loss, defaults to False. + :type hessian: bool, optional + """ + + def __init__( + self, + layer_dims, + learning_rate_dict, + params_dict, + loss_function, + input_tensors_list, + orig_factor_matrices, + force_function_list, + tensor_dtype, + use_attention=False, + activation="tanh", + hessian=False, + ): + super(DenseModel, self).__init__() + self.layer_dims = layer_dims + self.use_attention = use_attention + self.activation = activation + self.layer_list = [] + self.loss_function = loss_function + self.hessian = hessian + + self.tensor_dtype = tensor_dtype + + # if dtype is not a valid tensorflow dtype, raise an error + if not isinstance(self.tensor_dtype, tf.DType): + raise TypeError("The given dtype is not a valid tensorflow dtype") + + self.orig_factor_matrices = orig_factor_matrices + self.shape_function_mat_list = copy.deepcopy(orig_factor_matrices[0]) + self.shape_function_grad_x_factor_mat_list = copy.deepcopy(orig_factor_matrices[1]) + self.shape_function_grad_y_factor_mat_list = copy.deepcopy(orig_factor_matrices[2]) + + self.force_function_list = force_function_list + + self.input_tensors_list = input_tensors_list + self.input_tensor = copy.deepcopy(input_tensors_list[0]) + self.dirichlet_input = copy.deepcopy(input_tensors_list[1]) + self.dirichlet_actual = copy.deepcopy(input_tensors_list[2]) + + self.params_dict = params_dict + + self.pre_multiplier_val = self.shape_function_mat_list + self.pre_multiplier_grad_x = self.shape_function_grad_x_factor_mat_list + self.pre_multiplier_grad_y = self.shape_function_grad_y_factor_mat_list + + self.force_matrix = self.force_function_list + + print(f"{'-'*74}") + print(f"| {'PARAMETER':<25} | {'SHAPE':<25} |") + print(f"{'-'*74}") + print( + f"| {'input_tensor':<25} | {str(self.input_tensor.shape):<25} | {self.input_tensor.dtype}" + ) + print( + f"| {'force_matrix':<25} | {str(self.force_matrix.shape):<25} | {self.force_matrix.dtype}" + ) + print( + f"| {'pre_multiplier_grad_x':<25} | {str(self.pre_multiplier_grad_x.shape):<25} | {self.pre_multiplier_grad_x.dtype}" + ) + print( + f"| {'pre_multiplier_grad_y':<25} | {str(self.pre_multiplier_grad_y.shape):<25} | {self.pre_multiplier_grad_y.dtype}" + ) + print( + f"| {'pre_multiplier_val':<25} | {str(self.pre_multiplier_val.shape):<25} | {self.pre_multiplier_val.dtype}" + ) + print( + f"| {'dirichlet_input':<25} | {str(self.dirichlet_input.shape):<25} | {self.dirichlet_input.dtype}" + ) + print( + f"| {'dirichlet_actual':<25} | {str(self.dirichlet_actual.shape):<25} | {self.dirichlet_actual.dtype}" + ) + print(f"{'-'*74}") + + self.n_cells = params_dict["n_cells"] + + ## ----------------------------------------------------------------- ## + ## ---------- LEARNING RATE AND OPTIMISER FOR THE MODEL ------------ ## + ## ----------------------------------------------------------------- ## + + # parse the learning rate dictionary + self.learning_rate_dict = learning_rate_dict + initial_learning_rate = learning_rate_dict["initial_learning_rate"] + use_lr_scheduler = learning_rate_dict["use_lr_scheduler"] + decay_steps = learning_rate_dict["decay_steps"] + decay_rate = learning_rate_dict["decay_rate"] + # staircase = learning_rate_dict["staircase"] + + if use_lr_scheduler: + learning_rate_fn = tf.keras.optimizers.schedules.ExponentialDecay( + initial_learning_rate, decay_steps, decay_rate, staircase=True + ) + else: + learning_rate_fn = initial_learning_rate + + self.optimizer = tf.keras.optimizers.Adam(learning_rate=learning_rate_fn) + + ## ----------------------------------------------------------------- ## + ## --------------------- MODEL ARCHITECTURE ------------------------ ## + ## ----------------------------------------------------------------- ## + + # Build dense layers based on the input list + for dim in range(len(self.layer_dims) - 2): + self.layer_list.append( + layers.Dense( + self.layer_dims[dim + 1], + activation=self.activation, + kernel_initializer="glorot_uniform", + dtype=self.tensor_dtype, + bias_initializer="zeros", + ) + ) + + # Add a output layer with no activation + self.layer_list.append( + layers.Dense( + self.layer_dims[-1], + activation=None, + kernel_initializer="glorot_uniform", + dtype=self.tensor_dtype, + bias_initializer="zeros", + ) + ) + + # Add attention layer if required + if self.use_attention: + self.attention_layer = layers.Attention() + + # Compile the model + self.compile(optimizer=self.optimizer) + self.build(input_shape=(None, self.layer_dims[0])) + + # print the summary of the model + self.summary() + + # def build(self, input_shape): + # super(DenseModel, self).build(input_shape) + +
+[docs] + def call(self, inputs): + """ + The call method for the model. + + :param inputs: The input tensor for the model. + :type inputs: tf.Tensor + :return: The output tensor of the model. + :rtype: tf.Tensor + """ + x = inputs + + # Apply attention layer after input if flag is True + if self.use_attention: + x = self.attention_layer([x, x]) + + # Loop through the dense layers + for layer in self.layer_list: + x = layer(x) + + return x
+ + +
+[docs] + def get_config(self): + """ + Get the configuration of the model. + + Returns: + dict: The configuration of the model. + """ + # Get the base configuration + base_config = super().get_config() + + # Add the non-serializable arguments to the configuration + base_config.update( + { + "learning_rate_dict": self.learning_rate_dict, + "loss_function": self.loss_function, + "input_tensors_list": self.input_tensors_list, + "orig_factor_matrices": self.orig_factor_matrices, + "force_function_list": self.force_function_list, + "params_dict": self.params_dict, + "use_attention": self.use_attention, + "activation": self.activation, + "hessian": self.hessian, + "layer_dims": self.layer_dims, + "tensor_dtype": self.tensor_dtype, + } + ) + + return base_config
+ + +
+[docs] + @tf.function + def train_step(self, beta=10, bilinear_params_dict=None): # pragma: no cover + """ + The train step method for the model. + + :param beta: The beta parameter for the training step, defaults to 10. + :type beta: int, optional + :param bilinear_params_dict: The dictionary containing the bilinear parameters, defaults to None. + :type bilinear_params_dict: dict, optional + :return: The output of the training step. + :rtype: varies based on implementation + """ + + with tf.GradientTape(persistent=True) as tape: + # Predict the values for dirichlet boundary conditions + predicted_values_dirichlet = self(self.dirichlet_input) + + # initialize total loss as a tensor with shape (1,) and value 0.0 + total_pde_loss = 0.0 + + with tf.GradientTape(persistent=True) as tape1: + # tape gradient + tape1.watch(self.input_tensor) + # Compute the predicted values from the model + predicted_values = self(self.input_tensor) + + # compute the gradients of the predicted values wrt the input which is (x, y) + gradients = tape1.gradient(predicted_values, self.input_tensor) + + # Split the gradients into x and y components and reshape them to (-1, 1) + # the reshaping is done for the tensorial operations purposes (refer Notebook) + pred_grad_x = tf.reshape( + gradients[:, 0], [self.n_cells, self.pre_multiplier_grad_x.shape[-1]] + ) # shape : (N_cells , N_quadrature_points) + pred_grad_y = tf.reshape( + gradients[:, 1], [self.n_cells, self.pre_multiplier_grad_y.shape[-1]] + ) # shape : (N_cells , N_quadrature_points) + + pred_val = tf.reshape( + predicted_values, [self.n_cells, self.pre_multiplier_val.shape[-1]] + ) # shape : (N_cells , N_quadrature_points) + + cells_residual = self.loss_function( + test_shape_val_mat=self.pre_multiplier_val, + test_grad_x_mat=self.pre_multiplier_grad_x, + test_grad_y_mat=self.pre_multiplier_grad_y, + pred_nn=pred_val, + pred_grad_x_nn=pred_grad_x, + pred_grad_y_nn=pred_grad_y, + forcing_function=self.force_matrix, + bilinear_params=bilinear_params_dict, + ) + + residual = tf.reduce_sum(cells_residual) + + # Compute the total loss for the PDE + total_pde_loss = total_pde_loss + residual + + # print shapes of the predicted values and the actual values + boundary_loss = tf.reduce_mean( + tf.square(predicted_values_dirichlet - self.dirichlet_actual), axis=0 + ) + + # Compute Total Loss + total_loss = total_pde_loss + beta * boundary_loss + + trainable_vars = self.trainable_variables + self.gradients = tape.gradient(total_loss, trainable_vars) + self.optimizer.apply_gradients(zip(self.gradients, trainable_vars)) + + return {"loss_pde": total_pde_loss, "loss_dirichlet": boundary_loss, "loss": total_loss}
+
+ +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/fastvpinns/model/model_hard.html b/_modules/fastvpinns/model/model_hard.html new file mode 100644 index 0000000..1db3676 --- /dev/null +++ b/_modules/fastvpinns/model/model_hard.html @@ -0,0 +1,459 @@ + + + + + + fastvpinns.model.model_hard — fastvpinns 1.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for fastvpinns.model.model_hard

+"""
+file: model_hard.py
+description: This file contains the DenseModel class which is a custom model for the Neural Network
+                for solving Variational PINNs. This model is used for enforcing hard boundary constraints
+                on the solution.
+author: Thivin Anandh D, Divij Ghose, Sashikumaar Ganesan
+date: 22/01/2024
+changelog: 22/01/2024 - file created
+           22/01/2024 - 
+
+known issues: None
+"""
+
+import copy
+import numpy as np
+import tensorflow as tf
+from tensorflow.keras import layers
+from tensorflow.keras import initializers
+
+
+# Custom Model
+
+[docs] +class DenseModel_Hard(tf.keras.Model): + """The DenseModel_Hard class is a custom model class that hosts the neural network model. + + The class inherits from the tf.keras.Model class and is used + to define the neural network model architecture and the training loop for FastVPINNs. + :param layer_dims: List of integers representing the number of neurons in each layer + :type layer_dims: list + :param learning_rate_dict: Dictionary containing the learning rate parameters + :type learning_rate_dict: dict + :param params_dict: Dictionary containing the parameters for the model + :type params_dict: dict + :param loss_function: Loss function for the model + :type loss_function: function + :param input_tensors_list: List of input tensors for the model + :type input_tensors_list: list + :param orig_factor_matrices: List of original factor matrices + :type orig_factor_matrices: list + :param force_function_list: List of force functions + :type force_function_list: list + :param tensor_dtype: Tensor data type + :type tensor_dtype: tf.DType + :param use_attention: Flag to use attention layer + :type use_attention: bool + :param activation: Activation function for the model + :type activation: str + :param hessian: Flag to compute hessian + :type hessian: bool + + Methods + ------- + call(inputs) + This method is used to define the forward pass of the model. + get_config() + This method is used to get the configuration of the model. + train_step(beta=10, bilinear_params_dict=None) + This method is used to define the training step of the model. + + """ + + def __init__( + self, + layer_dims, + learning_rate_dict, + params_dict, + loss_function, + input_tensors_list, + orig_factor_matrices, + force_function_list, + tensor_dtype, + use_attention=False, + activation="tanh", + hessian=False, + hard_constraint_function=None, + ): + super(DenseModel_Hard, self).__init__() + self.layer_dims = layer_dims + self.use_attention = use_attention + self.activation = activation + self.layer_list = [] + self.loss_function = loss_function + self.hessian = hessian + if hard_constraint_function is None: + self.hard_constraint_function = lambda x, y: y + else: + self.hard_constraint_function = hard_constraint_function + + self.tensor_dtype = tensor_dtype + + # if dtype is not a valid tensorflow dtype, raise an error + if not isinstance(self.tensor_dtype, tf.DType): + raise TypeError("The given dtype is not a valid tensorflow dtype") + + self.orig_factor_matrices = orig_factor_matrices + self.shape_function_mat_list = copy.deepcopy(orig_factor_matrices[0]) + self.shape_function_grad_x_factor_mat_list = copy.deepcopy(orig_factor_matrices[1]) + self.shape_function_grad_y_factor_mat_list = copy.deepcopy(orig_factor_matrices[2]) + + self.force_function_list = force_function_list + + self.input_tensors_list = input_tensors_list + self.input_tensor = copy.deepcopy(input_tensors_list[0]) + self.dirichlet_input = copy.deepcopy(input_tensors_list[1]) + self.dirichlet_actual = copy.deepcopy(input_tensors_list[2]) + + self.params_dict = params_dict + + self.pre_multiplier_val = self.shape_function_mat_list + self.pre_multiplier_grad_x = self.shape_function_grad_x_factor_mat_list + self.pre_multiplier_grad_y = self.shape_function_grad_y_factor_mat_list + + self.force_matrix = self.force_function_list + + self.gradients = None + + print(f"{'-'*74}") + print(f"| {'PARAMETER':<25} | {'SHAPE':<25} |") + print(f"{'-'*74}") + print( + f"| {'input_tensor':<25} | {str(self.input_tensor.shape):<25} | {self.input_tensor.dtype}" + ) + print( + f"| {'force_matrix':<25} | {str(self.force_matrix.shape):<25} | {self.force_matrix.dtype}" + ) + print( + f"| {'pre_multiplier_grad_x':<25} | {str(self.pre_multiplier_grad_x.shape):<25} | {self.pre_multiplier_grad_x.dtype}" + ) + print( + f"| {'pre_multiplier_grad_y':<25} | {str(self.pre_multiplier_grad_y.shape):<25} | {self.pre_multiplier_grad_y.dtype}" + ) + print( + f"| {'pre_multiplier_val':<25} | {str(self.pre_multiplier_val.shape):<25} | {self.pre_multiplier_val.dtype}" + ) + print( + f"| {'dirichlet_input':<25} | {str(self.dirichlet_input.shape):<25} | {self.dirichlet_input.dtype}" + ) + print( + f"| {'dirichlet_actual':<25} | {str(self.dirichlet_actual.shape):<25} | {self.dirichlet_actual.dtype}" + ) + print(f"{'-'*74}") + + self.n_cells = params_dict["n_cells"] + + ## ----------------------------------------------------------------- ## + ## ---------- LEARNING RATE AND OPTIMISER FOR THE MODEL ------------ ## + ## ----------------------------------------------------------------- ## + + # parse the learning rate dictionary + self.learning_rate_dict = learning_rate_dict + initial_learning_rate = learning_rate_dict["initial_learning_rate"] + use_lr_scheduler = learning_rate_dict["use_lr_scheduler"] + decay_steps = learning_rate_dict["decay_steps"] + decay_rate = learning_rate_dict["decay_rate"] + staircase = learning_rate_dict["staircase"] + + if use_lr_scheduler: + learning_rate_fn = tf.keras.optimizers.schedules.ExponentialDecay( + initial_learning_rate, decay_steps, decay_rate, staircase=True + ) + else: + learning_rate_fn = initial_learning_rate + + self.optimizer = tf.keras.optimizers.Adam(learning_rate=learning_rate_fn) + + ## ----------------------------------------------------------------- ## + ## --------------------- MODEL ARCHITECTURE ------------------------ ## + ## ----------------------------------------------------------------- ## + + # Build dense layers based on the input list + for dim in range(len(self.layer_dims) - 2): + self.layer_list.append( + layers.Dense( + self.layer_dims[dim + 1], + activation=self.activation, + kernel_initializer="glorot_uniform", + dtype=self.tensor_dtype, + bias_initializer="zeros", + ) + ) + + # Add a output layer with no activation + self.layer_list.append( + layers.Dense( + self.layer_dims[-1], + activation=None, + kernel_initializer="glorot_uniform", + dtype=self.tensor_dtype, + bias_initializer="zeros", + ) + ) + + # Add attention layer if required + if self.use_attention: + self.attention_layer = layers.Attention() + + # Compile the model + self.compile(optimizer=self.optimizer) + self.build(input_shape=(None, self.layer_dims[0])) + + # print the summary of the model + self.summary() + + # def build(self, input_shape): + # super(DenseModel, self).build(input_shape) + +
+[docs] + def call(self, inputs): + """This method is used to define the forward pass of the model. + :param inputs: Input tensor + :type inputs: tf.Tensor + :return: Output tensor from the model + :rtype: tf.Tensor + """ + x = inputs + + # Apply attention layer after input if flag is True + if self.use_attention: + x = self.attention_layer([x, x]) + + # Loop through the dense layers + for layer in self.layer_list: + x = layer(x) + + x = self.hard_constraint_function(inputs, x) + + return x
+ + +
+[docs] + def get_config(self): + """This method is used to get the configuration of the model. + :return: Configuration of the model + :rtype: dict + """ + # Get the base configuration + base_config = super().get_config() + + # Add the non-serializable arguments to the configuration + base_config.update( + { + "learning_rate_dict": self.learning_rate_dict, + "loss_function": self.loss_function, + "input_tensors_list": self.input_tensors_list, + "orig_factor_matrices": self.orig_factor_matrices, + "force_function_list": self.force_function_list, + "params_dict": self.params_dict, + "use_attention": self.use_attention, + "activation": self.activation, + "hessian": self.hessian, + "layer_dims": self.layer_dims, + "tensor_dtype": self.tensor_dtype, + } + ) + + return base_config
+ + +
+[docs] + @tf.function + def train_step(self, beta=10, bilinear_params_dict=None): # pragma: no cover + """This method is used to define the training step of the mode. + :param bilinear_params_dict: Dictionary containing the bilinear parameters + :type bilinear_params_dict: dict + :return: Dictionary containing the loss values + :rtype: dict + """ + + with tf.GradientTape(persistent=True) as tape: + # Predict the values for dirichlet boundary conditions + + # initialize total loss as a tensor with shape (1,) and value 0.0 + total_pde_loss = 0.0 + + with tf.GradientTape(persistent=True) as tape1: + # tape gradient + tape1.watch(self.input_tensor) + # Compute the predicted values from the model + predicted_values = self(self.input_tensor) + + # compute the gradients of the predicted values wrt the input which is (x, y) + gradients = tape1.gradient(predicted_values, self.input_tensor) + + # Split the gradients into x and y components and reshape them to (-1, 1) + # the reshaping is done for the tensorial operations purposes (refer Notebook) + pred_grad_x = tf.reshape( + gradients[:, 0], [self.n_cells, self.pre_multiplier_grad_x.shape[-1]] + ) # shape : (N_cells , N_quadrature_points) + pred_grad_y = tf.reshape( + gradients[:, 1], [self.n_cells, self.pre_multiplier_grad_y.shape[-1]] + ) # shape : (N_cells , N_quadrature_points) + + pred_val = tf.reshape( + predicted_values, [self.n_cells, self.pre_multiplier_val.shape[-1]] + ) # shape : (N_cells , N_quadrature_points) + + cells_residual = self.loss_function( + test_shape_val_mat=self.pre_multiplier_val, + test_grad_x_mat=self.pre_multiplier_grad_x, + test_grad_y_mat=self.pre_multiplier_grad_y, + pred_nn=pred_val, + pred_grad_x_nn=pred_grad_x, + pred_grad_y_nn=pred_grad_y, + forcing_function=self.force_matrix, + bilinear_params=bilinear_params_dict, + ) + + residual = tf.reduce_sum(cells_residual) + + # tf.print("Residual : ", residual) + # tf.print("Residual Shape : ", residual.shape) + + # Compute the total loss for the PDE + total_pde_loss = total_pde_loss + residual + + # convert predicted_values_dirichlet to tf.float64 + # predicted_values_dirichlet = tf.cast(predicted_values_dirichlet, tf.float64) + + # tf.print("Boundary Loss : ", boundary_loss) + # tf.print("Boundary Loss Shape : ", boundary_loss.shape) + # tf.print("Total PDE Loss : ", total_pde_loss) + # tf.print("Total PDE Loss Shape : ", total_pde_loss.shape) + boundary_loss = 0.0 + # Compute Total Loss + total_loss = total_pde_loss + + trainable_vars = self.trainable_variables + self.gradients = tape.gradient(total_loss, trainable_vars) + self.optimizer.apply_gradients(zip(self.gradients, trainable_vars)) + + return {"loss_pde": total_pde_loss, "loss_dirichlet": boundary_loss, "loss": total_loss}
+
+ +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/fastvpinns/model/model_inverse.html b/_modules/fastvpinns/model/model_inverse.html new file mode 100644 index 0000000..3a2877f --- /dev/null +++ b/_modules/fastvpinns/model/model_inverse.html @@ -0,0 +1,469 @@ + + + + + + fastvpinns.model.model_inverse — fastvpinns 1.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + + +
  • +
  • +
+
+
+
+
+ +

Source code for fastvpinns.model.model_inverse

+"""
+file: model_inverse.py
+description: This file hosts the Neural Network (NN) model and the training loop for variational Physics-Informed Neural Networks (PINNs).
+             This focuses on training variational PINNs for inverse problems where the inverse parameter is constant on the domain.
+             The focus is on the model architecture and the training loop, and not on the loss functions.
+authors: Thivin Anandh D
+changelog: 22/Sep/2023 - Initial implementation with basic model architecture and training loop
+known_issues: Currently out of the box, supports only one constant inverse parameters.
+dependencies: None specified.
+"""
+
+import tensorflow as tf
+from tensorflow.keras import layers
+from tensorflow.keras import initializers
+import copy
+
+
+# Custom Model
+
+[docs] +class DenseModel_Inverse(tf.keras.Model): + """ + A subclass of tf.keras.Model that defines a dense model for an inverse problem. + + :param list layer_dims: The dimensions of the layers in the model. + :param dict learning_rate_dict: A dictionary containing the learning rates. + :param dict params_dict: A dictionary containing the parameters of the model. + :param function loss_function: The loss function to be used in the model. + :param list input_tensors_list: A list of input tensors. + :param list orig_factor_matrices: The original factor matrices. + :param list force_function_list: A list of force functions. + :param list sensor_list: A list of sensors for the inverse problem. + :param dict inverse_params_dict: A dictionary containing the parameters for the inverse problem. + :param tf.DType tensor_dtype: The data type of the tensors. + :param bool use_attention: Whether to use attention mechanism in the model. Defaults to False. + :param str activation: The activation function to be used in the model. Defaults to 'tanh'. + :param bool hessian: Whether to use Hessian in the model. Defaults to False. + """ + + def __init__( + self, + layer_dims, + learning_rate_dict, + params_dict, + loss_function, + input_tensors_list, + orig_factor_matrices, + force_function_list, + sensor_list, # for inverse problem + inverse_params_dict, # for inverse problem + tensor_dtype, + use_attention=False, + activation="tanh", + hessian=False, + ): + super(DenseModel_Inverse, self).__init__() + self.layer_dims = layer_dims + self.use_attention = use_attention + self.activation = activation + self.layer_list = [] + self.loss_function = loss_function + self.hessian = hessian + + self.tensor_dtype = tensor_dtype + + self.sensor_list = sensor_list + # obtain sensor values + self.sensor_points = sensor_list[0] + self.sensor_values = sensor_list[1] + + # inverse params dict + self.inverse_params_dict = inverse_params_dict + + # Conver all the values within inverse_params_dict to trainable variables + for key, value in self.inverse_params_dict.items(): + self.inverse_params_dict[key] = tf.Variable( + value, dtype=self.tensor_dtype, trainable=True + ) + tf.print(f"Key : {key} , Value : {self.inverse_params_dict[key]}") + + # add the sensor points to the trainable variables of the model + self.trainable_variables.extend(self.inverse_params_dict.values()) + + # if dtype is not a valid tensorflow dtype, raise an error + if not isinstance(self.tensor_dtype, tf.DType): + raise TypeError("The given dtype is not a valid tensorflow dtype") + + self.orig_factor_matrices = orig_factor_matrices + self.shape_function_mat_list = copy.deepcopy(orig_factor_matrices[0]) + self.shape_function_grad_x_factor_mat_list = copy.deepcopy(orig_factor_matrices[1]) + self.shape_function_grad_y_factor_mat_list = copy.deepcopy(orig_factor_matrices[2]) + + self.force_function_list = force_function_list + + self.input_tensors_list = input_tensors_list + self.input_tensor = copy.deepcopy(input_tensors_list[0]) + self.dirichlet_input = copy.deepcopy(input_tensors_list[1]) + self.dirichlet_actual = copy.deepcopy(input_tensors_list[2]) + + self.params_dict = params_dict + + self.pre_multiplier_val = self.shape_function_mat_list + self.pre_multiplier_grad_x = self.shape_function_grad_x_factor_mat_list + self.pre_multiplier_grad_y = self.shape_function_grad_y_factor_mat_list + + self.force_matrix = self.force_function_list + + print(f"{'-'*74}") + print(f"| {'PARAMETER':<25} | {'SHAPE':<25} |") + print(f"{'-'*74}") + print( + f"| {'input_tensor':<25} | {str(self.input_tensor.shape):<25} | {self.input_tensor.dtype}" + ) + print( + f"| {'force_matrix':<25} | {str(self.force_matrix.shape):<25} | {self.force_matrix.dtype}" + ) + print( + f"| {'pre_multiplier_grad_x':<25} | {str(self.pre_multiplier_grad_x.shape):<25} | {self.pre_multiplier_grad_x.dtype}" + ) + print( + f"| {'pre_multiplier_grad_y':<25} | {str(self.pre_multiplier_grad_y.shape):<25} | {self.pre_multiplier_grad_y.dtype}" + ) + print( + f"| {'pre_multiplier_val':<25} | {str(self.pre_multiplier_val.shape):<25} | {self.pre_multiplier_val.dtype}" + ) + print( + f"| {'dirichlet_input':<25} | {str(self.dirichlet_input.shape):<25} | {self.dirichlet_input.dtype}" + ) + print( + f"| {'dirichlet_actual':<25} | {str(self.dirichlet_actual.shape):<25} | {self.dirichlet_actual.dtype}" + ) + print(f"{'-'*74}") + + self.n_cells = params_dict["n_cells"] + + ## ----------------------------------------------------------------- ## + ## ---------- LEARNING RATE AND OPTIMISER FOR THE MODEL ------------ ## + ## ----------------------------------------------------------------- ## + + # parse the learning rate dictionary + self.learning_rate_dict = learning_rate_dict + initial_learning_rate = learning_rate_dict["initial_learning_rate"] + use_lr_scheduler = learning_rate_dict["use_lr_scheduler"] + decay_steps = learning_rate_dict["decay_steps"] + decay_rate = learning_rate_dict["decay_rate"] + staircase = learning_rate_dict["staircase"] + + if use_lr_scheduler: + learning_rate_fn = tf.keras.optimizers.schedules.ExponentialDecay( + initial_learning_rate, decay_steps, decay_rate, staircase=True + ) + else: + learning_rate_fn = initial_learning_rate + + self.optimizer = tf.keras.optimizers.Adam(learning_rate=learning_rate_fn) + + ## ----------------------------------------------------------------- ## + ## --------------------- MODEL ARCHITECTURE ------------------------ ## + ## ----------------------------------------------------------------- ## + + # Build dense layers based on the input list + for dim in range(len(self.layer_dims) - 2): + self.layer_list.append( + layers.Dense( + self.layer_dims[dim + 1], + activation=self.activation, + kernel_initializer="glorot_uniform", + dtype=self.tensor_dtype, + bias_initializer="zeros", + ) + ) + + # Add a output layer with no activation + self.layer_list.append( + layers.Dense( + self.layer_dims[-1], + activation=None, + kernel_initializer="glorot_uniform", + dtype=self.tensor_dtype, + bias_initializer="zeros", + ) + ) + + # Add attention layer if required + if self.use_attention: + self.attention_layer = layers.Attention() + + # Compile the model + self.compile(optimizer=self.optimizer) + self.build(input_shape=(None, self.layer_dims[0])) + + # print the summary of the model + self.summary() + +
+[docs] + def call(self, inputs): + """ + Applies the model to the input data. + + Args: + inputs: The input data. + + Returns: + The output of the model after applying all the layers. + """ + x = inputs + + # Apply attention layer after input if flag is True + if self.use_attention: + x = self.attention_layer([x, x]) + + # Loop through the dense layers + for layer in self.layer_list: + x = layer(x) + + return x
+ + +
+[docs] + def get_config(self): + """ + Returns the configuration of the model. + + This method is used to serialize the model configuration. It returns a dictionary + containing all the necessary information to recreate the model. + + Returns: + dict: The configuration dictionary of the model. + """ + # Get the base configuration + base_config = super().get_config() + + # Add the non-serializable arguments to the configuration + base_config.update( + { + "learning_rate_dict": self.learning_rate_dict, + "loss_function": self.loss_function, + "input_tensors_list": self.input_tensors_list, + "orig_factor_matrices": self.orig_factor_matrices, + "force_function_list": self.force_function_list, + "params_dict": self.params_dict, + "use_attention": self.use_attention, + "activation": self.activation, + "hessian": self.hessian, + "layer_dims": self.layer_dims, + "tensor_dtype": self.tensor_dtype, + "sensor_list": self.sensor_list, + "inverse_params_dict": self.inverse_params_dict, + } + ) + + return base_config
+ + +
+[docs] + @tf.function + def train_step(self, beta=10, bilinear_params_dict=None): # pragma: no cover + + with tf.GradientTape(persistent=True) as tape: + # Predict the values for dirichlet boundary conditions + predicted_values_dirichlet = self(self.dirichlet_input) + + # predict the sensor values + predicted_sensor_values = self(self.sensor_points) + + # initialize total loss as a tensor with shape (1,) and value 0.0 + total_pde_loss = 0.0 + + with tf.GradientTape(persistent=True) as tape1: + # tape gradient + tape1.watch(self.input_tensor) + # Compute the predicted values from the model + predicted_values = self(self.input_tensor) + + # compute the gradients of the predicted values wrt the input which is (x, y) + gradients = tape1.gradient(predicted_values, self.input_tensor) + + # Split the gradients into x and y components and reshape them to (-1, 1) + # the reshaping is done for the tensorial operations purposes (refer Notebook) + pred_grad_x = tf.reshape( + gradients[:, 0], [self.n_cells, self.pre_multiplier_grad_x.shape[-1]] + ) # shape : (N_cells , N_quadrature_points) + pred_grad_y = tf.reshape( + gradients[:, 1], [self.n_cells, self.pre_multiplier_grad_y.shape[-1]] + ) # shape : (N_cells , N_quadrature_points) + + pred_val = tf.reshape( + predicted_values, [self.n_cells, self.pre_multiplier_val.shape[-1]] + ) # shape : (N_cells , N_quadrature_points) + + cells_residual = self.loss_function( + test_shape_val_mat=self.pre_multiplier_val, + test_grad_x_mat=self.pre_multiplier_grad_x, + test_grad_y_mat=self.pre_multiplier_grad_y, + pred_nn=pred_val, + pred_grad_x_nn=pred_grad_x, + pred_grad_y_nn=pred_grad_y, + forcing_function=self.force_matrix, + bilinear_params=bilinear_params_dict, + inverse_params_dict=self.inverse_params_dict, + ) + + residual = tf.reduce_sum(cells_residual) + + # tf.print("Residual : ", residual) + # tf.print("Residual Shape : ", residual.shape) + + # Compute the total loss for the PDE + total_pde_loss = total_pde_loss + residual + + # convert predicted_values_dirichlet to tf.float64 + # predicted_values_dirichlet = tf.cast(predicted_values_dirichlet, tf.float64) + + # print shapes of the predicted values and the actual values + boundary_loss = tf.reduce_mean( + tf.square(predicted_values_dirichlet - self.dirichlet_actual), axis=0 + ) + + # Sensor loss + sensor_loss = tf.reduce_mean( + tf.square(predicted_sensor_values - self.sensor_values), axis=0 + ) + + # tf.print("Boundary Loss : ", boundary_loss) + # tf.print("Boundary Loss Shape : ", boundary_loss.shape) + # tf.print("Total PDE Loss : ", total_pde_loss) + # tf.print("Total PDE Loss Shape : ", total_pde_loss.shape) + + # Compute Total Loss + total_loss = total_pde_loss + beta * boundary_loss + 10 * sensor_loss + + trainable_vars = self.trainable_variables + self.gradients = tape.gradient(total_loss, trainable_vars) + self.optimizer.apply_gradients(zip(self.gradients, trainable_vars)) + + return { + "loss_pde": total_pde_loss, + "loss_dirichlet": boundary_loss, + "loss": total_loss, + "inverse_params": self.inverse_params_dict, + "sensor_loss": sensor_loss, + }
+
+ +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/fastvpinns/model/model_inverse_domain.html b/_modules/fastvpinns/model/model_inverse_domain.html new file mode 100644 index 0000000..a08a13b --- /dev/null +++ b/_modules/fastvpinns/model/model_inverse_domain.html @@ -0,0 +1,474 @@ + + + + + + fastvpinns.model.model_inverse_domain — fastvpinns 1.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + + +
  • +
  • +
+
+
+
+
+ +

Source code for fastvpinns.model.model_inverse_domain

+"""
+file: model_inverse_domain.py
+description: This file hosts the Neural Network (NN) model and the training loop for variational Physics-Informed Neural Networks (PINNs).
+             This focuses on training variational PINNs for inverse problems where the inverse parameter is constant over the entire domain.
+             The focus is on the model architecture and the training loop, and not on the loss functions.
+authors: Thivin Anandh D
+changelog: 22/Sep/2023 - Initial implementation with basic model architecture and training loop
+known_issues: None
+dependencies: None specified.
+"""
+
+import tensorflow as tf
+from tensorflow.keras import layers
+from tensorflow.keras import initializers
+import copy
+
+
+# Custom Model
+
+[docs] +class DenseModel_Inverse_Domain(tf.keras.Model): + """ + A subclass of tf.keras.Model that defines a dense model for an inverse problem. + + :param list layer_dims: The dimensions of the layers in the model. + :param dict learning_rate_dict: A dictionary containing the learning rates. + :param dict params_dict: A dictionary containing the parameters of the model. + :param function loss_function: The loss function to be used in the model. + :param list input_tensors_list: A list of input tensors. + :param list orig_factor_matrices: The original factor matrices. + :param list force_function_list: A list of force functions. + :param list sensor_list: A list of sensors for the inverse problem. + :param dict inverse_params_dict: A dictionary containing the parameters for the inverse problem. + :param tf.DType tensor_dtype: The data type of the tensors. + :param bool use_attention: Whether to use attention mechanism in the model. Defaults to False. + :param str activation: The activation function to be used in the model. Defaults to 'tanh'. + :param bool hessian: Whether to use Hessian in the model. Defaults to False. + """ + + def __init__( + self, + layer_dims, + learning_rate_dict, + params_dict, + loss_function, + input_tensors_list, + orig_factor_matrices, + force_function_list, + sensor_list, # for inverse problem + tensor_dtype, + use_attention=False, + activation="tanh", + hessian=False, + ): + super(DenseModel_Inverse_Domain, self).__init__() + self.layer_dims = layer_dims + self.use_attention = use_attention + self.activation = activation + self.layer_list = [] + self.loss_function = loss_function + self.hessian = hessian + + self.tensor_dtype = tensor_dtype + + self.sensor_list = sensor_list + # obtain sensor values + self.sensor_points = sensor_list[0] + self.sensor_values = sensor_list[1] + + # if dtype is not a valid tensorflow dtype, raise an error + if not isinstance(self.tensor_dtype, tf.DType): + raise TypeError("The given dtype is not a valid tensorflow dtype") + + self.orig_factor_matrices = orig_factor_matrices + self.shape_function_mat_list = copy.deepcopy(orig_factor_matrices[0]) + self.shape_function_grad_x_factor_mat_list = copy.deepcopy(orig_factor_matrices[1]) + self.shape_function_grad_y_factor_mat_list = copy.deepcopy(orig_factor_matrices[2]) + + self.force_function_list = force_function_list + + self.input_tensors_list = input_tensors_list + self.input_tensor = copy.deepcopy(input_tensors_list[0]) + self.dirichlet_input = copy.deepcopy(input_tensors_list[1]) + self.dirichlet_actual = copy.deepcopy(input_tensors_list[2]) + + self.params_dict = params_dict + + self.pre_multiplier_val = self.shape_function_mat_list + self.pre_multiplier_grad_x = self.shape_function_grad_x_factor_mat_list + self.pre_multiplier_grad_y = self.shape_function_grad_y_factor_mat_list + + self.force_matrix = self.force_function_list + + print(f"{'-'*74}") + print(f"| {'PARAMETER':<25} | {'SHAPE':<25} |") + print(f"{'-'*74}") + print( + f"| {'input_tensor':<25} | {str(self.input_tensor.shape):<25} | {self.input_tensor.dtype}" + ) + print( + f"| {'force_matrix':<25} | {str(self.force_matrix.shape):<25} | {self.force_matrix.dtype}" + ) + print( + f"| {'pre_multiplier_grad_x':<25} | {str(self.pre_multiplier_grad_x.shape):<25} | {self.pre_multiplier_grad_x.dtype}" + ) + print( + f"| {'pre_multiplier_grad_y':<25} | {str(self.pre_multiplier_grad_y.shape):<25} | {self.pre_multiplier_grad_y.dtype}" + ) + print( + f"| {'pre_multiplier_val':<25} | {str(self.pre_multiplier_val.shape):<25} | {self.pre_multiplier_val.dtype}" + ) + print( + f"| {'dirichlet_input':<25} | {str(self.dirichlet_input.shape):<25} | {self.dirichlet_input.dtype}" + ) + print( + f"| {'dirichlet_actual':<25} | {str(self.dirichlet_actual.shape):<25} | {self.dirichlet_actual.dtype}" + ) + print(f"{'-'*74}") + + self.n_cells = params_dict["n_cells"] + + ## ----------------------------------------------------------------- ## + ## ---------- LEARNING RATE AND OPTIMISER FOR THE MODEL ------------ ## + ## ----------------------------------------------------------------- ## + + # parse the learning rate dictionary + self.learning_rate_dict = learning_rate_dict + initial_learning_rate = learning_rate_dict["initial_learning_rate"] + use_lr_scheduler = learning_rate_dict["use_lr_scheduler"] + decay_steps = learning_rate_dict["decay_steps"] + decay_rate = learning_rate_dict["decay_rate"] + # staircase = learning_rate_dict["staircase"] + + if use_lr_scheduler: + learning_rate_fn = tf.keras.optimizers.schedules.ExponentialDecay( + initial_learning_rate, decay_steps, decay_rate, staircase=True + ) + else: + learning_rate_fn = initial_learning_rate + + self.optimizer = tf.keras.optimizers.Adam(learning_rate=learning_rate_fn) + + # build the model using the input shape of the first layer in self.layer_dims + input_shape = (None, self.layer_dims[0]) + # build the model + self.build(input_shape=input_shape) + # Compile the model + self.compile(optimizer=self.optimizer) + # print model summary + self.summary() + + ## ----------------------------------------------------------------- ## + ## --------------------- MODEL ARCHITECTURE ------------------------ ## + ## ----------------------------------------------------------------- ## + + # Build dense layers based on the input list + for dim in range(len(self.layer_dims) - 2): + self.layer_list.append( + layers.Dense( + self.layer_dims[dim + 1], + activation=self.activation, + kernel_initializer="glorot_uniform", + dtype=self.tensor_dtype, + bias_initializer="zeros", + ) + ) + + # Add a output layer with no activation + self.layer_list.append( + layers.Dense( + self.layer_dims[-1], + activation=None, + kernel_initializer="glorot_uniform", + dtype=self.tensor_dtype, + bias_initializer="zeros", + ) + ) + + # Add attention layer if required + if self.use_attention: + self.attention_layer = layers.Attention() + + # Compile the model + self.compile(optimizer=self.optimizer) + self.build(input_shape=(None, self.layer_dims[0])) + + # print the summary of the model + self.summary() + +
+[docs] + def call(self, inputs): + """ + The call method for the model. + + :param inputs: The input tensor for the model. + :type inputs: tf.Tensor + :return: The output tensor of the model. + :rtype: tf.Tensor + """ + x = inputs + + # Apply attention layer after input if flag is True + if self.use_attention: + x = self.attention_layer([x, x]) + + # Loop through the dense layers + for layer in self.layer_list: + x = layer(x) + + return x
+ + +
+[docs] + def get_config(self): + """ + Get the configuration of the model. + + Returns: + dict: The configuration of the model. + """ + # Get the base configuration + base_config = super().get_config() + + # Add the non-serializable arguments to the configuration + base_config.update( + { + "learning_rate_dict": self.learning_rate_dict, + "loss_function": self.loss_function, + "input_tensors_list": self.input_tensors_list, + "orig_factor_matrices": self.orig_factor_matrices, + "force_function_list": self.force_function_list, + "params_dict": self.params_dict, + "use_attention": self.use_attention, + "activation": self.activation, + "hessian": self.hessian, + "layer_dims": self.layer_dims, + "tensor_dtype": self.tensor_dtype, + "sensor_list": self.sensor_list, + } + ) + + return base_config
+ + +
+[docs] + @tf.function + def train_step(self, beta=10, bilinear_params_dict=None): # pragma: no cover + """ + The train step method for the model. + + :param beta: The beta parameter for the training step, defaults to 10. + :type beta: int, optional + :param bilinear_params_dict: The dictionary containing the bilinear parameters, defaults to None. + :type bilinear_params_dict: dict, optional + :return: The output of the training step. + :rtype: varies based on implementation + """ + + with tf.GradientTape(persistent=True) as tape: + # Predict the values for dirichlet boundary conditions + predicted_values_dirichlet = self(self.dirichlet_input) + # reshape the predicted values to (, 1) + predicted_values_dirichlet = tf.reshape(predicted_values_dirichlet[:, 0], [-1, 1]) + + # predict the sensor values + predicted_sensor_values = self(self.sensor_points) + # reshape the predicted values to (, 1) + predicted_sensor_values = tf.reshape(predicted_sensor_values[:, 0], [-1, 1]) + + # initialize total loss as a tensor with shape (1,) and value 0.0 + total_pde_loss = 0.0 + + with tf.GradientTape(persistent=True) as tape1: + # tape gradient + tape1.watch(self.input_tensor) + # Compute the predicted values from the model + predicted_values_actual = self(self.input_tensor) + + predicted_values = predicted_values_actual[:, 0] + inverse_param_values = predicted_values_actual[:, 1] + + # compute the gradients of the predicted values wrt the input which is (x, y) + # First column of the predicted values is the predicted value of the PDE + gradients = tape1.gradient(predicted_values, self.input_tensor) + + # obtain inverse param gradients + inverse_param_gradients = tape1.gradient(inverse_param_values, self.input_tensor) + + # Split the gradients into x and y components and reshape them to (-1, 1) + # the reshaping is done for the tensorial operations purposes (refer Notebook) + pred_grad_x = tf.reshape( + gradients[:, 0], [self.n_cells, self.pre_multiplier_grad_x.shape[-1]] + ) # shape : (N_cells , N_quadrature_points) + pred_grad_y = tf.reshape( + gradients[:, 1], [self.n_cells, self.pre_multiplier_grad_y.shape[-1]] + ) # shape : (N_cells , N_quadrature_points) + + # First column of the predicted values is the predicted value of the PDE and reshape it to (N_cells, N_quadrature_points) + pred_val = tf.reshape( + predicted_values, [self.n_cells, self.pre_multiplier_val.shape[-1]] + ) # shape : (N_cells , N_quadrature_points) + + # reshape the second column of the predicted value and reshape it to (N_cells, N_quadrature_points) + inverse_param_values = tf.reshape( + inverse_param_values, [self.n_cells, self.pre_multiplier_val.shape[-1]] + ) # shape : (N_cells , N_quadrature_points) + + cells_residual = self.loss_function( + test_shape_val_mat=self.pre_multiplier_val, + test_grad_x_mat=self.pre_multiplier_grad_x, + test_grad_y_mat=self.pre_multiplier_grad_y, + pred_nn=pred_val, + pred_grad_x_nn=pred_grad_x, + pred_grad_y_nn=pred_grad_y, + forcing_function=self.force_matrix, + bilinear_params=bilinear_params_dict, + inverse_params_list=[inverse_param_values], + ) + + residual = tf.reduce_sum(cells_residual) + + # Compute the total loss for the PDE + total_pde_loss = total_pde_loss + residual + + # print shapes of the predicted values and the actual values + boundary_loss = tf.reduce_mean( + tf.square(predicted_values_dirichlet - self.dirichlet_actual), axis=0 + ) + + # Sensor loss + sensor_loss = tf.reduce_mean( + tf.square(predicted_sensor_values - self.sensor_values), axis=0 + ) + + # Compute Total Loss + total_loss = total_pde_loss + beta * boundary_loss + 10 * sensor_loss + + trainable_vars = self.trainable_variables + self.gradients = tape.gradient(total_loss, trainable_vars) + self.optimizer.apply_gradients(zip(self.gradients, trainable_vars)) + + return { + "loss_pde": total_pde_loss, + "loss_dirichlet": boundary_loss, + "loss": total_loss, + "sensor_loss": sensor_loss, + }
+
+ +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/fastvpinns/physics/cd2d.html b/_modules/fastvpinns/physics/cd2d.html new file mode 100644 index 0000000..0a16b44 --- /dev/null +++ b/_modules/fastvpinns/physics/cd2d.html @@ -0,0 +1,203 @@ + + + + + + fastvpinns.physics.cd2d — fastvpinns 1.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for fastvpinns.physics.cd2d

+"""
+This function is implemntation of our efficient tensor-based loss calculation for cd2d equation
+Author: Thivin Anandh D
+Date: 21-Sep-2023
+History: Initial implementation
+Refer: https://arxiv.org/abs/2404.12063
+"""
+
+import tensorflow as tf
+
+
+# PDE loss function for the cd2d problem
+
+[docs] +@tf.function +def pde_loss_cd2d( + test_shape_val_mat, + test_grad_x_mat, + test_grad_y_mat, + pred_nn, + pred_grad_x_nn, + pred_grad_y_nn, + forcing_function, + bilinear_params, +): # pragma: no cover + """ + Calculates and returns the loss for the CD2D problem + + :param test_shape_val_mat: The test shape value matrix. + :type test_shape_val_mat: tf.Tensor + :param test_grad_x_mat: The x-gradient of the test matrix. + :type test_grad_x_mat: tf.Tensor + :param test_grad_y_mat: The y-gradient of the test matrix. + :type test_grad_y_mat: tf.Tensor + :param pred_nn: The predicted neural network output. + :type pred_nn: tf.Tensor + :param pred_grad_x_nn: The x-gradient of the predicted neural network output. + :type pred_grad_x_nn: tf.Tensor + :param pred_grad_y_nn: The y-gradient of the predicted neural network output. + :type pred_grad_y_nn: tf.Tensor + :param forcing_function: The forcing function used in the PDE. + :type forcing_function: function + :param bilinear_params: The parameters for the bilinear form. + :type bilinear_params: list + + + :return: The calculated loss. + :rtype: tf.Tensor + """ + + # Loss Function : ∫du/dx. dv/dx + ∫du/dy. dv/dy - ∫f.v + + # ∫du/dx. dv/dx dΩ + pde_diffusion_x = tf.transpose(tf.linalg.matvec(test_grad_x_mat, pred_grad_x_nn)) + + # ∫du/dy. dv/dy dΩ + pde_diffusion_y = tf.transpose(tf.linalg.matvec(test_grad_y_mat, pred_grad_y_nn)) + + # eps * ∫ (du/dx. dv/dx + du/dy. dv/dy) dΩ + pde_diffusion = bilinear_params["eps"] * (pde_diffusion_x + pde_diffusion_y) + + # ∫du/dx. v dΩ + conv_x = tf.transpose(tf.linalg.matvec(test_shape_val_mat, pred_grad_x_nn)) + + # # ∫du/dy. v dΩ + conv_y = tf.transpose(tf.linalg.matvec(test_shape_val_mat, pred_grad_y_nn)) + + # # b(x) * ∫du/dx. v dΩ + b(y) * ∫du/dy. v dΩ + conv = bilinear_params["b_x"] * conv_x + bilinear_params["b_y"] * conv_y + + # reaction term + # ∫c.u.v dΩ + reaction = bilinear_params["c"] * tf.transpose(tf.linalg.matvec(test_shape_val_mat, pred_nn)) + + residual_matrix = (pde_diffusion + conv + reaction) - forcing_function + + # Perform Reduce mean along the axis 0 + residual_cells = tf.reduce_mean(tf.square(residual_matrix), axis=0) + + return residual_cells
+ +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/fastvpinns/physics/cd2d_inverse.html b/_modules/fastvpinns/physics/cd2d_inverse.html new file mode 100644 index 0000000..eecb2bf --- /dev/null +++ b/_modules/fastvpinns/physics/cd2d_inverse.html @@ -0,0 +1,207 @@ + + + + + + fastvpinns.physics.cd2d_inverse — fastvpinns 1.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + + +
  • +
  • +
+
+
+
+
+ +

Source code for fastvpinns.physics.cd2d_inverse

+"""
+This function is implemntation of our efficient tensor-based loss calculation for cd2d equation with inverse problem (Constant)
+Author: Thivin Anandh D
+Date: 21-Sep-2023
+History: Initial implementation
+Refer: https://arxiv.org/abs/2404.12063
+"""
+
+import tensorflow as tf
+
+
+# PDE loss function for the CD2D problem Inverse (constant)
+# @tf.function  #- Commented due to compatibility issues
+
+[docs] +def pde_loss_cd2d( + test_shape_val_mat, + test_grad_x_mat, + test_grad_y_mat, + pred_nn, + pred_grad_x_nn, + pred_grad_y_nn, + forcing_function, + bilinear_params_dict, + inverse_param_dict, +): # pragma: no cover + """ + Calculates and returns the loss for the CD2D problem Inverse (constant) + + :param test_shape_val_mat: The test shape value matrix. + :type test_shape_val_mat: tf.Tensor + :param test_grad_x_mat: The x-gradient of the test matrix. + :type test_grad_x_mat: tf.Tensor + :param test_grad_y_mat: The y-gradient of the test matrix. + :type test_grad_y_mat: tf.Tensor + :param pred_nn: The predicted neural network output. + :type pred_nn: tf.Tensor + :param pred_grad_x_nn: The x-gradient of the predicted neural network output. + :type pred_grad_x_nn: tf.Tensor + :param pred_grad_y_nn: The y-gradient of the predicted neural network output. + :type pred_grad_y_nn: tf.Tensor + :param forcing_function: The forcing function used in the PDE. + :type forcing_function: function + :param bilinear_params_dict: The dictionary containing the bilinear parameters. + :type bilinear_params_dict: dict + :param inverse_param_dict: The dictionary containing the parameters for the inverse problem. + :type inverse_param_dict: dict + + :return: The calculated loss. + :rtype: tf.Tensor + """ + + # Loss Function : ∫du/dx. dv/dx + ∫du/dy. dv/dy - ∫f.v + + # ∫du/dx. dv/dx dΩ + pde_diffusion_x = tf.transpose(tf.linalg.matvec(test_grad_x_mat, pred_grad_x_nn)) + + # ∫du/dy. dv/dy dΩ + pde_diffusion_y = tf.transpose(tf.linalg.matvec(test_grad_y_mat, pred_grad_y_nn)) + + # eps * ∫ (du/dx. dv/dx + du/dy. dv/dy) dΩ + pde_diffusion = inverse_param_dict["eps"] * (pde_diffusion_x + pde_diffusion_y) + + # ∫du/dx. v dΩ + conv_x = tf.transpose(tf.linalg.matvec(test_shape_val_mat, pred_grad_x_nn)) + + # # ∫du/dy. v dΩ + conv_y = tf.transpose(tf.linalg.matvec(test_shape_val_mat, pred_grad_y_nn)) + + # # b(x) * ∫du/dx. v dΩ + b(y) * ∫du/dy. v dΩ + conv = bilinear_params_dict["b_x"] * conv_x + bilinear_params_dict["b_y"] * conv_y + + # reaction term + # ∫c.u.v dΩ + reaction = bilinear_params_dict["c"] * tf.transpose( + tf.linalg.matvec(test_shape_val_mat, pred_nn) + ) + + residual_matrix = (pde_diffusion + conv + reaction) - forcing_function + + # Perform Reduce mean along the axis 0 + residual_cells = tf.reduce_mean(tf.square(residual_matrix), axis=0) + + return residual_cells
+ +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/fastvpinns/physics/cd2d_inverse_domain.html b/_modules/fastvpinns/physics/cd2d_inverse_domain.html new file mode 100644 index 0000000..54b0978 --- /dev/null +++ b/_modules/fastvpinns/physics/cd2d_inverse_domain.html @@ -0,0 +1,211 @@ + + + + + + fastvpinns.physics.cd2d_inverse_domain — fastvpinns 1.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + + +
  • +
  • +
+
+
+
+
+ +

Source code for fastvpinns.physics.cd2d_inverse_domain

+"""
+This function is implemntation of our efficient tensor-based loss calculation for cd2d equation with inverse problem (Domain)
+Author: Thivin Anandh D
+Date: 21-Sep-2023
+History: Initial implementation
+Refer: https://arxiv.org/abs/2404.12063
+"""
+
+import tensorflow as tf
+
+
+# PDE loss function for the CD2D inverse problem (Domain)
+
+[docs] +@tf.function +def pde_loss_cd2d_inverse_domain( + test_shape_val_mat, + test_grad_x_mat, + test_grad_y_mat, + pred_nn, + pred_grad_x_nn, + pred_grad_y_nn, + forcing_function, + bilinear_params, + inverse_params_list, +): # pragma: no cover + """ + Calculates and returns the loss for the CD2D inverse problem (Domain) + + :param test_shape_val_mat: The test shape value matrix. + :type test_shape_val_mat: tf.Tensor + :param test_grad_x_mat: The x-gradient of the test matrix. + :type test_grad_x_mat: tf.Tensor + :param test_grad_y_mat: The y-gradient of the test matrix. + :type test_grad_y_mat: tf.Tensor + :param pred_nn: The predicted neural network output. + :type pred_nn: tf.Tensor + :param pred_grad_x_nn: The x-gradient of the predicted neural network output. + :type pred_grad_x_nn: tf.Tensor + :param pred_grad_y_nn: The y-gradient of the predicted neural network output. + :type pred_grad_y_nn: tf.Tensor + :param forcing_function: The forcing function used in the PDE. + :type forcing_function: function + :param bilinear_params: The parameters for the bilinear form. + :type bilinear_params: list + :param inverse_params_list: The parameters for the inverse problem. + :type inverse_params_list: list + + :return: The calculated loss. + :rtype: tf.Tensor + """ + + # The first values in the inverse_params_list is the number of inverse problems + diffusion_coeff_NN = inverse_params_list[0] + + # ∫ε.du/dx. dv/dx dΩ + pde_diffusion_x = tf.transpose( + tf.linalg.matvec(test_grad_x_mat, pred_grad_x_nn * diffusion_coeff_NN) + ) + + # ∫ε.du/dy. dv/dy dΩ + pde_diffusion_y = tf.transpose( + tf.linalg.matvec(test_grad_y_mat, pred_grad_y_nn * diffusion_coeff_NN) + ) + + # eps * ∫ (du/dx. dv/dx + du/dy. dv/dy) dΩ + # Here our eps is a variable which is to be learned, Which is already premultiplied with the predicted gradient of the neural network + pde_diffusion = pde_diffusion_x + pde_diffusion_y + + # ∫du/dx. v dΩ + conv_x = tf.transpose(tf.linalg.matvec(test_shape_val_mat, pred_grad_x_nn)) + + # # ∫du/dy. v dΩ + conv_y = tf.transpose(tf.linalg.matvec(test_shape_val_mat, pred_grad_y_nn)) + + # # b(x) * ∫du/dx. v dΩ + b(y) * ∫du/dy. v dΩ + conv = bilinear_params["b_x"] * conv_x + bilinear_params["b_y"] * conv_y + + # reaction term + # ∫c.u.v dΩ + reaction = bilinear_params["c"] * tf.transpose(tf.linalg.matvec(test_shape_val_mat, pred_nn)) + + residual_matrix = (pde_diffusion + conv + reaction) - forcing_function + + # Perform Reduce mean along the axis 0 + residual_cells = tf.reduce_mean(tf.square(residual_matrix), axis=0) + + return residual_cells
+ +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/fastvpinns/physics/helmholtz2d.html b/_modules/fastvpinns/physics/helmholtz2d.html new file mode 100644 index 0000000..8b459eb --- /dev/null +++ b/_modules/fastvpinns/physics/helmholtz2d.html @@ -0,0 +1,191 @@ + + + + + + fastvpinns.physics.helmholtz2d — fastvpinns 1.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + + +
  • +
  • +
+
+
+
+
+ +

Source code for fastvpinns.physics.helmholtz2d

+"""
+This function is implemntation of our efficient tensor-based loss calculation for Helmholtz equation with inverse problem (Domain)
+Author: Thivin Anandh D
+Date: 21-Sep-2023
+History: Initial implementation
+Refer: https://arxiv.org/abs/2404.12063
+"""
+
+import tensorflow as tf
+
+
+# PDE loss function for the poisson problem
+
+[docs] +@tf.function +def pde_loss_helmholtz( + test_shape_val_mat, + test_grad_x_mat, + test_grad_y_mat, + pred_nn, + pred_grad_x_nn, + pred_grad_y_nn, + forcing_function, + bilinear_params, +): # pragma: no cover + """ + Calculates and returns the loss for the helmholtz problem + + :param test_shape_val_mat: The test shape value matrix. + :type test_shape_val_mat: tf.Tensor + :param test_grad_x_mat: The x-gradient of the test matrix. + :type test_grad_x_mat: tf.Tensor + :param test_grad_y_mat: The y-gradient of the test matrix. + :type test_grad_y_mat: tf.Tensor + :param pred_nn: The predicted neural network output. + :type pred_nn: tf.Tensor + :param pred_grad_x_nn: The x-gradient of the predicted neural network output. + :type pred_grad_x_nn: tf.Tensor + :param pred_grad_y_nn: The y-gradient of the predicted neural network output. + :type pred_grad_y_nn: tf.Tensor + :param forcing_function: The forcing function used in the PDE. + :type forcing_function: function + :param bilinear_params: The parameters for the bilinear form. + :type bilinear_params: list + + + :return: The calculated loss. + :rtype: tf.Tensor + """ + # ∫ (du/dx. dv/dx ) dΩ + pde_diffusion_x = tf.transpose(tf.linalg.matvec(test_grad_x_mat, pred_grad_x_nn)) + + # ∫ (du/dy. dv/dy ) dΩ + pde_diffusion_y = tf.transpose(tf.linalg.matvec(test_grad_y_mat, pred_grad_y_nn)) + + # eps * ∫ (du/dx. dv/dx + du/dy. dv/dy) dΩ + pde_diffusion = bilinear_params["eps"] * (pde_diffusion_x + pde_diffusion_y) + + # \int(k^2 (u).v) dw + helmholtz_additional = (bilinear_params["k"] ** 2) * tf.transpose( + tf.linalg.matvec(test_shape_val_mat, pred_nn) + ) + + residual_matrix = -1.0 * (pde_diffusion) + helmholtz_additional - forcing_function + + residual_cells = tf.reduce_mean(tf.square(residual_matrix), axis=0) + + return residual_cells
+ +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/fastvpinns/physics/poisson2d.html b/_modules/fastvpinns/physics/poisson2d.html new file mode 100644 index 0000000..324649e --- /dev/null +++ b/_modules/fastvpinns/physics/poisson2d.html @@ -0,0 +1,165 @@ + + + + + + fastvpinns.physics.poisson2d — fastvpinns 1.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for fastvpinns.physics.poisson2d

+"""
+This function is implemntation of our efficient tensor-based loss calculation for poisson equation
+Author: Thivin Anandh D
+Date: 21-Sep-2023
+History: Initial implementation
+Refer: https://arxiv.org/abs/2404.12063
+"""
+
+import tensorflow as tf
+
+
+# PDE loss function for the poisson problem
+
+[docs] +@tf.function +def pde_loss_poisson( + test_shape_val_mat, + test_grad_x_mat, + test_grad_y_mat, + pred_nn, + pred_grad_x_nn, + pred_grad_y_nn, + forcing_function, + bilinear_params, +): # pragma: no cover + """ + This method returns the loss for the Poisson Problem of the PDE + """ + # ∫du/dx. dv/dx dΩ + pde_diffusion_x = tf.transpose(tf.linalg.matvec(test_grad_x_mat, pred_grad_x_nn)) + + # ∫du/dy. dv/dy dΩ + pde_diffusion_y = tf.transpose(tf.linalg.matvec(test_grad_y_mat, pred_grad_y_nn)) + + # eps * ∫ (du/dx. dv/dx + du/dy. dv/dy) dΩ + pde_diffusion = bilinear_params["eps"] * (pde_diffusion_x + pde_diffusion_y) + + residual_matrix = pde_diffusion - forcing_function + + residual_cells = tf.reduce_mean(tf.square(residual_matrix), axis=0) + + return residual_cells
+ +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/fastvpinns/physics/poisson2d_inverse.html b/_modules/fastvpinns/physics/poisson2d_inverse.html new file mode 100644 index 0000000..83fb369 --- /dev/null +++ b/_modules/fastvpinns/physics/poisson2d_inverse.html @@ -0,0 +1,188 @@ + + + + + + fastvpinns.physics.poisson2d_inverse — fastvpinns 1.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + + +
  • +
  • +
+
+
+
+
+ +

Source code for fastvpinns.physics.poisson2d_inverse

+"""
+This function is implemntation of our efficient tensor-based loss calculation for poisson equation with inverse problem (constant)
+Author: Thivin Anandh D
+Date: 21-Sep-2023
+History: Initial implementation
+Refer: https://arxiv.org/abs/2404.12063
+"""
+
+import tensorflow as tf
+
+
+# PDE loss function for the poisson problem inverse
+# @tf.function - Commented due to compatibility issues
+
+[docs] +def pde_loss_poisson_inverse( + test_shape_val_mat, + test_grad_x_mat, + test_grad_y_mat, + pred_nn, + pred_grad_x_nn, + pred_grad_y_nn, + forcing_function, + bilinear_params, + inverse_params_dict, +): # pragma: no cover + """ + Calculates and returns the loss for the Poisson problem Inverse (constant) + + :param test_shape_val_mat: The test shape value matrix. + :type test_shape_val_mat: tf.Tensor + :param test_grad_x_mat: The x-gradient of the test matrix. + :type test_grad_x_mat: tf.Tensor + :param test_grad_y_mat: The y-gradient of the test matrix. + :type test_grad_y_mat: tf.Tensor + :param pred_nn: The predicted neural network output. + :type pred_nn: tf.Tensor + :param pred_grad_x_nn: The x-gradient of the predicted neural network output. + :type pred_grad_x_nn: tf.Tensor + :param pred_grad_y_nn: The y-gradient of the predicted neural network output. + :type pred_grad_y_nn: tf.Tensor + :param forcing_function: The forcing function used in the PDE. + :type forcing_function: function + :param bilinear_params_dict: The dictionary containing the bilinear parameters. + :type bilinear_params_dict: dict + :param inverse_param_dict: The dictionary containing the parameters for the inverse problem. + :type inverse_param_dict: dict + + :return: The calculated loss. + :rtype: tf.Tensor + """ + # ∫du/dx. dv/dx dΩ + pde_diffusion_x = tf.transpose(tf.linalg.matvec(test_grad_x_mat, pred_grad_x_nn)) + + # ∫du/dy. dv/dy dΩ + pde_diffusion_y = tf.transpose(tf.linalg.matvec(test_grad_y_mat, pred_grad_y_nn)) + + # eps * ∫ (du/dx. dv/dx + du/dy. dv/dy) dΩ + pde_diffusion = inverse_params_dict["eps"] * (pde_diffusion_x + pde_diffusion_y) + + residual_matrix = pde_diffusion - forcing_function + + residual_cells = tf.reduce_mean(tf.square(residual_matrix), axis=0) + + return residual_cells
+ +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/fastvpinns/utils/compute_utils.html b/_modules/fastvpinns/utils/compute_utils.html new file mode 100644 index 0000000..b612625 --- /dev/null +++ b/_modules/fastvpinns/utils/compute_utils.html @@ -0,0 +1,330 @@ + + + + + + fastvpinns.utils.compute_utils — fastvpinns 1.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + + +
  • +
  • +
+
+
+
+
+ +

Source code for fastvpinns.utils.compute_utils

+"""
+filename: compute_utils.py
+description: This file contains the utility functions for 
+             computing the errors between the exact and 
+             predicted solutions
+author: Thivin Anandh D
+date: 02/11/2023
+changelog: 02/11/2023 - file created
+           02/11/2023 - added functions to compute L1, L2, L_inf errors
+
+known_issues: None
+"""
+
+# Importing the required libraries
+import numpy as np
+
+
+
+[docs] +def compute_l2_error(u_exact, u_approx): + """This function will compute the L2 error between the exact solution and the approximate solution. + The L2 error is defined as: + + ..math:: + \\sqrt{\\frac{1}{N} \\sum_{i=1}^{N} (u_{exact} - u_{approx})^2} + + :param u_exact: numpy array containing the exact solution + :type u_exact: numpy.ndarray + :param u_approx: numpy array containing the approximate solution + :type u_approx: numpy.ndarray + :return: L2 error between the exact and approximate solutions + :rtype: float + """ + # Flatten the arrays + u_exact = u_exact.flatten() + u_approx = u_approx.flatten() + + # compute the L2 error + l2_error = np.sqrt(np.mean(np.square(u_exact - u_approx))) + return l2_error
+ + + +
+[docs] +def compute_l1_error(u_exact, u_approx): + """This function will compute the L1 error between the exact solution and the approximate solution. + The L1 error is defined as: + ..math:: + \\frac{1}{N} \\sum_{i=1}^{N} |u_{exact} - u_{approx}| + :param u_exact: numpy array containing the exact solution + :type u_exact: numpy.ndarray + :param u_approx: numpy array containing the approximate solution + :type u_approx: numpy.ndarray + :return: L1 error between the exact and approximate solutions + :rtype: float + """ + # Flatten the arrays + u_exact = u_exact.flatten() + u_approx = u_approx.flatten() + # compute the L1 error + l1_error = np.mean(np.abs(u_exact - u_approx)) + return l1_error
+ + + +
+[docs] +def compute_linf_error(u_exact, u_approx): + """This function will compute the L_inf error between the exact solution and the approximate solution. + The L_inf error is defined as + ..math:: + \\max_{i=1}^{N} |u_{exact} - u_{approx}| + :param u_exact: numpy array containing the exact solution + :type u_exact: numpy.ndarray + :param u_approx: numpy array containing the approximate solution + :type u_approx: numpy.ndarray + :return: L_inf error between the exact and approximate solutions + :rtype: float + """ + # flatten the arrays + u_exact = u_exact.flatten() + u_approx = u_approx.flatten() + + # compute the L_inf error + linf_error = np.max(np.abs(u_exact - u_approx)) + return linf_error
+ + + +
+[docs] +def compute_l2_error_relative(u_exact, u_approx): + """This function will compute the relative L2 error between the exact solution and the approximate solution. + The relative L2 error is defined as: + ..math:: + \\frac{\\sqrt{\\frac{1}{N} \\sum_{i=1}^{N} (u_{exact} - u_{approx})^2}}{\\sqrt{\\frac{1}{N} \\sum_{i=1}^{N} u_{exact}^2}} + :param u_exact: numpy array containing the exact solution + :type u_exact: numpy.ndarray + :param u_approx: numpy array containing the approximate solution + :type u_approx: numpy.ndarray + :return: relative L2 error between the exact and approximate solutions + :rtype: float + """ + # flatten the arrays + u_exact = u_exact.flatten() + u_approx = u_approx.flatten() + + # compute the L2 error + l2_error = compute_l2_error(u_exact, u_approx) + # compute the relative L2 error + l2_error_relative = l2_error / np.sqrt(np.mean(np.square(u_exact))) + return l2_error_relative
+ + + +
+[docs] +def compute_linf_error_relative(u_exact, u_approx): + """This function will compute the relative L_inf error between the exact solution and the approximate solution. + The relative L_inf error is defined as: + ..math:: + \\frac{\\max_{i=1}^{N} |u_{exact} - u_{approx}|}{\\max_{i=1}^{N} |u_{exact}|} + :param u_exact: numpy array containing the exact solution + :type u_exact: numpy.ndarray + :param u_approx: numpy array containing the approximate solution + :type u_approx: numpy.ndarray + :return: relative L_inf error between the exact and approximate solutions + :rtype: float + """ + # flatten the arrays + u_exact = u_exact.flatten() + u_approx = u_approx.flatten() + + # compute the L_inf error + linf_error = compute_linf_error(u_exact, u_approx) + # compute the relative L_inf error + linf_error_relative = linf_error / np.max(np.abs(u_exact)) + return linf_error_relative
+ + + +
+[docs] +def compute_l1_error_relative(u_exact, u_approx): + """This function will compute the relative L1 error between the exact solution and the approximate solution. + The relative L1 error is defined as: + ..math:: + \\frac{\\frac{1}{N} \\sum_{i=1}^{N} |u_{exact} - u_{approx}|}{\\frac{1}{N} \\sum_{i=1}^{N} |u_{exact}|} + :param u_exact: numpy array containing the exact solution + :type u_exact: numpy.ndarray + :param u_approx: numpy array containing the approximate solution + :type u_approx: numpy.ndarray + :return: relative L1 error between the exact and approximate solutions + :rtype: float + """ + # flatten the arrays + u_exact = u_exact.flatten() + u_approx = u_approx.flatten() + + # compute the L2 error + l1_error = compute_l1_error(u_exact, u_approx) + # compute the relative l1 error + l1_error_relative = l1_error / np.mean(np.abs(u_exact)) + return l1_error_relative
+ + + +
+[docs] +def compute_errors_combined(u_exact, u_approx): + """This function will compute the L1, L2 and L_inf absolute and relative errors. + :param u_exact: numpy array containing the exact solution + :type u_exact: numpy.ndarray + :param u_approx: numpy array containing the approximate solution + :type u_approx: numpy.ndarray + :return: L1, L2 and L_inf absolute and relative errors + :rtype: tuple + + """ + # flatten the arrays + u_exact = u_exact.flatten() + u_approx = u_approx.flatten() + + # compute the L2 error + l2_error = compute_l2_error(u_exact, u_approx) + # compute the L_inf error + linf_error = compute_linf_error(u_exact, u_approx) + # compute the relative L2 error + l2_error_relative = compute_l2_error_relative(u_exact, u_approx) + # compute the relative L_inf error + linf_error_relative = compute_linf_error_relative(u_exact, u_approx) + + # compute L1 Error + l1_error = compute_l1_error(u_exact, u_approx) + + # compute the relative L1 error + l1_error_relative = compute_l1_error_relative(u_exact, u_approx) + + return ( + l2_error, + linf_error, + l2_error_relative, + linf_error_relative, + l1_error, + l1_error_relative, + )
+ +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/fastvpinns/utils/plot_utils.html b/_modules/fastvpinns/utils/plot_utils.html new file mode 100644 index 0000000..f5c6711 --- /dev/null +++ b/_modules/fastvpinns/utils/plot_utils.html @@ -0,0 +1,440 @@ + + + + + + fastvpinns.utils.plot_utils — fastvpinns 1.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for fastvpinns.utils.plot_utils

+"""
+filename: plot_utils.py
+description: This file contains the utility functions for
+              plotting the loss functions and the predicted inverse parameters
+
+author: Thivin Anandh D
+date: 02/11/2023
+changelog: 02/11/2023 - file created
+           02/11/2023 - added functions to plot the loss functions and the predicted 
+                        inverse parameters
+
+known_issues: None
+"""
+
+import matplotlib.pyplot as plt
+from cycler import cycler
+import numpy as np
+
+
+plt.rcParams["xtick.labelsize"] = 20
+plt.rcParams["axes.titlesize"] = 20
+plt.rcParams["axes.labelsize"] = 20
+
+plt.rcParams["legend.fontsize"] = 20
+plt.rcParams["ytick.labelsize"] = 20
+plt.rcParams["axes.prop_cycle"] = cycler(
+    color=[
+        "darkblue",
+        "#d62728",
+        "#2ca02c",
+        "#ff7f0e",
+        "#bcbd22",
+        "#8c564b",
+        "#17becf",
+        "#9467bd",
+        "#e377c2",
+        "#7f7f7f",
+    ]
+)
+
+
+# plot the loss function
+
+[docs] +def plot_loss_function(loss_function, output_path): + """This function will plot the loss function. + :param loss_function: list of loss values + :type loss_function: list + :param output_path: path to save the plot + :type output_path: str + :return: None + :rtype: None + """ + # plot the loss function + plt.figure(figsize=(6.4, 4.8)) + plt.plot(loss_function) + # plot y axis in log scale + plt.yscale("log") + plt.xlabel("Epochs") + plt.ylabel("Loss") + plt.title("Loss Function") + plt.tight_layout() + plt.grid() + plt.savefig(output_path + "/loss_function.png", dpi=300) + + plt.close()
+ + + +
+[docs] +def plot_array(array, output_path, filename, title, x_label="Epochs", y_label="Loss"): + """This function will plot the loss function. + :param array: list of loss values + :type array: list + :param output_path: path to save the plot + :type output_path: str + :param filename: filename to save the plot + :type filename: str + :param title: title of the plot + :type title: str + :param x_label: x-axis label, defaults to "Epochs" + :type x_label: str, optional + :param y_label: y-axis label, defaults to "Loss" + :type y_label: str, optional + :return: None + :rtype: None + """ + # plot the loss function + plt.figure(figsize=(6.4, 4.8)) + plt.plot(array) + # plot y axis in log scale + plt.yscale("log") + plt.xlabel(x_label) + plt.ylabel(y_label) + plt.title(title) + plt.tight_layout() + plt.grid() + plt.savefig(output_path + f"/{filename}.png", dpi=300) + plt.close()
+ + + +# general utility to plot multiple parameters +
+[docs] +def plot_multiple_loss_function( + loss_function_list, output_path, filename, legend_labels, y_label, title, x_label="Epochs" +): + """This function will plot the loss function in log scale for multiple parameters. + :param loss_function_list: list of loss values for multiple parameters + :type loss_function_list: list + :param output_path: path to save the plot + :type output_path: str + :param filename: filename to save the plot + :type filename: str + :param legend_labels: list of legend labels + :type legend_labels: list + :param y_label: y-axis label + :type y_label: str + :param title: title of the plot + :type title: str + :param x_label: x-axis label, defaults to "Epochs" + :type x_label: str, optional + :return: None + :rtype: None + """ + + # plot the loss function + plt.figure(figsize=(6.4, 4.8)) + for loss_function, label in zip(loss_function_list, legend_labels): + plt.plot(loss_function, label=label) + + # plot y axis in log scale + plt.yscale("log") + plt.xlabel(x_label) + plt.ylabel(y_label) + plt.title(title) + plt.tight_layout() + plt.legend() + plt.grid() + plt.savefig(output_path + f"/{filename}.png", dpi=300) + plt.close()
+ + + +# plot the loss function +
+[docs] +def plot_inverse_test_loss_function(loss_function, output_path): + """This function will plot the test loss function of the inverse parameter. + :param loss_function: list of loss values + :type loss_function: list + :param output_path: path to save the plot + :type output_path: str + :return: None + :rtype: None + """ + # plot the loss function + plt.figure(figsize=(6.4, 4.8)) + plt.plot(loss_function) + # plot y axis in log scale + plt.yscale("log") + plt.xlabel("Epochs") + plt.ylabel("Loss") + plt.title("Loss Function") + plt.tight_layout() + plt.savefig(output_path + "/test_inverse_loss_function.png", dpi=300) + plt.close()
+ + + +
+[docs] +def plot_test_loss_function(loss_function, output_path, fileprefix=""): + """This function will plot the test loss function. + :param loss_function: list of loss values + :type loss_function: list + :param output_path: path to save the plot + :type output_path: str + :param fileprefix: prefix for the filename, defaults to "" + :type fileprefix: str, optional + :return: None + :rtype: None + """ + # plot the loss function + plt.figure(figsize=(6.4, 4.8)) + plt.plot(loss_function) + # plot y axis in log scale + plt.yscale("log") + plt.xlabel("Epochs") + plt.ylabel("Loss") + plt.title("Loss Function") + plt.tight_layout() + if fileprefix == "": + plt.savefig(output_path + "/test_loss_function.png", dpi=300) + else: + plt.savefig(output_path + "/" + fileprefix + "_test_loss_function.png", dpi=300) + plt.close()
+ + + +
+[docs] +def plot_test_time_loss_function(time_array, loss_function, output_path): + """This function will plot the test loss as a function of time in seconds. + :param time_array: array of time values + :type time_array: numpy.ndarray + :param loss_function: list of loss values + :type loss_function: list + :param output_path: path to save the plot + :type output_path: str + :return: None + :rtype: None + """ + # plot the loss function + plt.figure(figsize=(6.4, 4.8)) + plt.plot(time_array, loss_function) + # plot y axis in log scale + plt.yscale("log") + plt.xscale("log") + plt.xlabel("Time [s]") + plt.ylabel("MAE Loss") + plt.title("Loss Function") + plt.tight_layout() + plt.savefig(output_path + "/test_time_loss_function.png", dpi=300) + plt.close()
+ + + +
+[docs] +def plot_contour(x, y, z, output_path, filename, title): + """This function will plot the contour plot. + :param x: x values + :type x: numpy.ndarray + :param y: y values + :type y: numpy.ndarray + :param z: z values + :type z: numpy.ndarray + :param output_path: path to save the plot + :type output_path: str + :param filename: filename to save the plot + :type filename: str + :param title: title of the plot + :type title: str + :return: None + :rtype: None + """ + + plt.figure(figsize=(6.4, 4.8)) + plt.contourf(x, y, z, levels=100, cmap="jet") + plt.title(title) + plt.colorbar() + plt.savefig(output_path + "/" + filename + ".png", dpi=300) + + plt.close()
+ + + +# plot the Inverse parameter prediction +
+[docs] +def plot_inverse_param_function( + inverse_predicted, inverse_param_name, actual_value, output_path, file_prefix +): + """This function will plot the predicted inverse parameter. + :param inverse_predicted: list of predicted inverse parameter values + :type inverse_predicted: list + :param inverse_param_name: name of the inverse parameter + :type inverse_param_name: str + :param actual_value: actual value of the inverse parameter + :type actual_value: float + :param output_path: path to save the plot + :type output_path: str + :param file_prefix: prefix for the filename + :type file_prefix: str + :return: None + :rtype: None + """ + # plot the loss function + plt.figure(figsize=(6.4, 4.8), dpi=300) + plt.plot(inverse_predicted, label="Predicted " + inverse_param_name) + + # draw a horizontal dotted line at the actual value + plt.hlines( + actual_value, + 0, + len(inverse_predicted), + colors="k", + linestyles="dashed", + label="Actual " + inverse_param_name, + ) + + # plot y axis in log scale + # plt.yscale("log") + plt.xlabel("Epochs") + plt.ylabel(inverse_param_name) + + # plt.title("Loss Function") + plt.tight_layout() + plt.legend() + plt.grid() + plt.savefig(output_path + f"/{file_prefix}.png", dpi=300) + plt.close() + + # plot the loss of inverse parameter + plt.figure(figsize=(6.4, 4.8), dpi=300) + actual_val_array = np.ones_like(inverse_predicted) * actual_value + plt.plot(abs(actual_val_array - inverse_predicted)) + plt.xlabel("Epochs") + plt.ylabel("Absolute Error") + plt.yscale("log") + plt.title("Absolute Error of " + inverse_param_name) + plt.tight_layout() + plt.savefig(output_path + f"/{file_prefix}_absolute_error.png", dpi=300) + plt.close()
+ +
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/fastvpinns/utils/print_utils.html b/_modules/fastvpinns/utils/print_utils.html new file mode 100644 index 0000000..5a016ba --- /dev/null +++ b/_modules/fastvpinns/utils/print_utils.html @@ -0,0 +1,169 @@ + + + + + + fastvpinns.utils.print_utils — fastvpinns 1.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for fastvpinns.utils.print_utils

+# File for Printing utilities
+# of all the cells within the given mesh
+# Author: Thivin Anandh D
+# Date:  02/Nov/2023
+
+from rich.console import Console
+from rich.table import Table
+
+
+
+
+
+ +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_modules/index.html b/_modules/index.html new file mode 100644 index 0000000..2032d3e --- /dev/null +++ b/_modules/index.html @@ -0,0 +1,148 @@ + + + + + + Overview: module code — fastvpinns 1.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + +
+
+ + + + \ No newline at end of file diff --git a/_rst/_cite.html b/_rst/_cite.html new file mode 100644 index 0000000..1f12d84 --- /dev/null +++ b/_rst/_cite.html @@ -0,0 +1,141 @@ + + + + + + + Cite FastVPINNs — fastvpinns 1.0.0 documentation + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Cite FastVPINNs

+

If you use fastvpinns for your research, please cite the following paper:

+
@misc{anandh2024fastvpinns,
+  title={FastVPINNs: Tensor-Driven Acceleration of VPINNs for Complex Geometries},
+  author={Thivin Anandh and Divij Ghose and Himanshu Jain and Sashikumaar Ganesan},
+  year={2024},
+  eprint={2404.12063},
+  archivePrefix={arXiv},
+  primaryClass={cs.LG}
+}
+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_rst/_contributing.html b/_rst/_contributing.html new file mode 100644 index 0000000..ece5f78 --- /dev/null +++ b/_rst/_contributing.html @@ -0,0 +1,140 @@ + + + + + + + How to Contribute — fastvpinns 1.0.0 documentation + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

How to Contribute

+

We welcome contributions to this project! Here are some guidelines to help you get started:

+
    +
  1. Open an Issue or Feature Request: Before starting your work, please open an issue or feature request. This allows us to assign the task to you and avoid duplicate work.

  2. +
  3. Fork and Create a Branch: Fork the repository and create a branch for your issue or feature. All changes should be made on this branch, not on the main branch.

  4. +
  5. Follow Coding Standards: Please use proper indentation and linting. Install pre-commit and run it locally to format files using the black library and check the linting score.

  6. +
  7. Write Tests: If you add new code, please also add corresponding test cases. Compute and update the test coverage by running build_release.py.

  8. +
  9. Commit Messages: Add a proper commit message that references the issue or feature request and includes well-documented comments.

  10. +
  11. Squash Commits: Before raising a Pull Request (PR), squash your commits on the feature branch into a single commit.

  12. +
+

Thank you for contributing!

+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_rst/_installation.html b/_rst/_installation.html new file mode 100644 index 0000000..bb66acd --- /dev/null +++ b/_rst/_installation.html @@ -0,0 +1,173 @@ + + + + + + + Installation — fastvpinns 1.0.0 documentation + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Installation

+

The build of the code is currently tested on Python 3.8, 3.9, 3.10 and 3.11. The code is CI tested on environments provided by Github Actions such as ubuntu-20.04, ubuntu-latest, macos-latest, windows-latest, +refer to Compatibility-CI page for more details.

+
+

Setting up an Virtual Environment

+

It is recommended to create a virtual environment to install the package. You can create a virtual environment using the following command:

+
python3 -m venv venv
+source venv/bin/activate
+
+
+

For conda users, you can create a virtual environment using the following command:

+
conda create -n fastvpinns python=3.8
+conda activate fastvpinns
+
+
+
+
+

Installing via PIP

+

You can simply install the package using pip as follows:

+
pip install fastvpinns
+
+
+

On ubuntu/mac systems with libGL issues caused due to matplotlib or gmsh, please run the following command to install the required dependencies.

+
sudo apt-get install libgl1-mesa-glx
+
+
+
+
+

Installing from source

+

The official distribution is on GitHub, and you can clone the repository using

+
git clone https://github.com/cmgcds/fastvpinns.git
+
+
+

To install the package just type:

+
cd fastvpinns
+pip install -e .
+
+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_rst/_licence.html b/_rst/_licence.html new file mode 100644 index 0000000..cbe0ba2 --- /dev/null +++ b/_rst/_licence.html @@ -0,0 +1,147 @@ + + + + + + + License — fastvpinns 1.0.0 documentation + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

License

+

MIT License

+

Copyright (c) [2024] [Thivin Anandh, Divij Ghose, Sashikumaar Ganesan]

+

Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the “Software”), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions:

+

The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software.

+

THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE.

+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_rst/_team.html b/_rst/_team.html new file mode 100644 index 0000000..e9a2f0d --- /dev/null +++ b/_rst/_team.html @@ -0,0 +1,132 @@ + + + + + + + FastVPINNs Team — fastvpinns 1.0.0 documentation + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

FastVPINNs Team

+

FastVPINNs is currently developed by Thivin Anandh, Divij Ghose, +under supervision of Prof. Sashikumaar Ganesan at STARS LAB, Indian Institute of Science, Bangalore.

+

The Authors would like to acknowledge the support of Shell Technology Centre, India for their partial funding, We are thankful to the MHRD Grant No. STARS-1/388 (SPADE) +for partial support.

+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_rst/_tutorial.html b/_rst/_tutorial.html new file mode 100644 index 0000000..3cb3291 --- /dev/null +++ b/_rst/_tutorial.html @@ -0,0 +1,198 @@ + + + + + + + FastVPINNs Tutorials — fastvpinns 1.0.0 documentation + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

FastVPINNs Tutorials

+

This page contains tutorials for solving 2D Partial Differential Equations (PDEs) using the FastVPINNs library. The tutorials are organized as follows:

+
+

Forward Problems

+
+

Problems on Uniform Mesh

+ +
+
+

Problems on Complex geometry

+ +
+
+

Problems with Hard boundary constraints

+ +
+
+
+

Inverse Problems

+ +
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_rst/fastvpinns.html b/_rst/fastvpinns.html new file mode 100644 index 0000000..08e53a4 --- /dev/null +++ b/_rst/fastvpinns.html @@ -0,0 +1,347 @@ + + + + + + + FastVPINNs Module Documentation — fastvpinns 1.0.0 documentation + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

FastVPINNs Module Documentation

+

This section covers the documentation of the FastVPINNs modules. The package is divided into several subpackages, each of which is documented in its own section. The main module documentation is provided below.

+
    +
  • FE - Finite Element routines for 2D domains

  • +
  • Geometry - Meshing and Geometry routines

  • +
  • Model - Dense Neural Network Model

  • +
  • Physics - Physics classes for the problem

  • +
  • Data - Data handling routines

  • +
  • Utils - Utility functions

  • +
+
+

FE

+
+

This section holds the documentation for the FE module of the FastVPINNs package. The module provides the necessary classes and functions to obtain the finite element test functions and quadrature points for the 2D domain within the FastVPINNs package. This section is broadly classified into

+
+
+
+

Finite Element Test Functions

+ +
+
+
+
+

Quadrature Functions

+ +
+
+
+
+

Finite Element Transformations

+ +
+
+
+
+

Finite Element Setup

+ +
+
+
+

Geometry

+
+

This section holds the documentation for the the geometry module of the FastVPINNs package. The module provides the necessary classes and functions to obtain the geometry information either from the external mesh file or from the internal mesh generation routines. This supports the generation of VTK and GMSH files for visualization purposes.

+ +
+
+

Model

+
+

This section holds the documentation for the the Model module of the FastVPINNs package. The module provides the necessary classes and functions to train a Variational physics informed neural network (VPINN) model for the given physics problem. The model contains only the information about the neural network architecture and the training process. The physics information is provided by the user in the form of a physics class. The model class is responsible for training the neural network and providing the necessary prediction functions.

+
+
+
+

Model Types

+ +
+
+
+

Physics

+
+

This section holds the documentation for the the Physics module of the FastVPINNs package. The module provides the necessary classes and functions to define the physics of the problem. The physics class contains the information about the governing equations and their loss calculation in the variational form.

+
+
+
+

Forward Problems

+ +
+
+

Inverse Problems (Constant Coefficient)

+ +
+
+

Inverse Problems (Spatially Varying Coefficient)

+ +
+
+
+

Data

+
+

This section holds the documentation for the the datahandler module of the FastVPINNs package. The module provides the necessary classes and functions to handle the data for the training of the VPINN model. The datahandler class is responsible for generating and assembling the tensors into required format for the training process.

+ +
+
+

Utils

+
+

This section holds the documentation for all the helper functions, which are responsible for plotting and console outputs.

+ +
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_rst/library/data/datahandler.html b/_rst/library/data/datahandler.html new file mode 100644 index 0000000..29e98e0 --- /dev/null +++ b/_rst/library/data/datahandler.html @@ -0,0 +1,262 @@ + + + + + + + fastvpinns.data.datahandler module — fastvpinns 1.0.0 documentation + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

fastvpinns.data.datahandler module

+
+
+class fastvpinns.data.datahandler.DataHandler(fespace, domain, dtype)[source]
+

Bases: object

+

This class is to handle data for 2D problems, convert them into tensors using custom tf functions. +It is responsible for all type conversions and data handling.

+
+

Note

+

All inputs to these functions are generally numpy arrays with dtype np.float64. +So we can either maintain the same dtype or convert them to tf.float32 ( for faster computation ).

+
+
+
Parameters:
+
    +
  • fespace (FESpace2D) – The FESpace2D object.

  • +
  • domain (Domain2D) – The Domain2D object.

  • +
  • shape_val_mat_list (list) – List of shape function values for each cell.

  • +
  • grad_x_mat_list (list) – List of shape function derivatives with respect to x for each cell.

  • +
  • grad_y_mat_list (list) – List of shape function derivatives with respect to y for each cell.

  • +
  • x_pde_list (list) – List of actual coordinates of the quadrature points for each cell.

  • +
  • forcing_function_list (list) – List of forcing function values for each cell.

  • +
  • dtype (tf.DType) – The tensorflow dtype to be used for all the tensors.

  • +
+
+
+
+
+abstract get_bilinear_params_dict_as_tensors(function)[source]
+

Accepts a function from example file and converts all the values into tensors of the given dtype

+

Parameters: +- function (function): The function from the example file which returns the bilinear parameters dictionary

+

Returns: +- bilinear_params_dict (dict): The bilinear parameters dictionary with all the values converted to tensors

+
+
Parameters:
+

function (function) – The function from the example file which returns the bilinear parameters dictionary

+
+
Returns:
+

The bilinear parameters dictionary with all the values converted to tensors

+
+
Return type:
+

dict

+
+
+
+ +
+
+abstract get_dirichlet_input()[source]
+

This function will return the input for the Dirichlet boundary data

+
+
Returns:
+

    +
  • input_dirichlet (tf.Tensor): The input for the Dirichlet boundary data

  • +
  • actual_dirichlet (tf.Tensor): The actual Dirichlet boundary data

  • +
+

+
+
+
+ +
+
+abstract get_inverse_params(inverse_params_dict_function)[source]
+

Accepts a function from example file and converts all the values into tensors of the given dtype

+
+
Parameters:
+

inverse_params_dict_function (function) – The function from the example file which returns the inverse parameters dictionary

+
+
Returns:
+

The inverse parameters dictionary with all the values converted to tensors

+
+
Return type:
+

dict

+
+
+
+ +
+
+abstract get_sensor_data(exact_sol, num_sensor_points, mesh_type, file_name=None)[source]
+

Accepts a function from example file and converts all the values into tensors of the given dtype

+
+
Parameters:
+
    +
  • exact_sol (function) – The function from the example file which returns the exact solution

  • +
  • num_sensor_points (int) – The number of sensor points to be generated

  • +
  • mesh_type (str) – The type of mesh to be used for sensor data generation

  • +
  • file_name (str, optional) – The name of the file to be used for external mesh generation, defaults to None

  • +
+
+
Returns:
+

The sensor points and sensor values as tensors

+
+
Return type:
+

tuple[tf.Tensor, tf.Tensor]

+
+
+
+ +
+
+abstract get_test_points()[source]
+

Get the test points for the given domain.

+
+
Returns:
+

The test points for the given domain.

+
+
Return type:
+

tf.Tensor

+
+
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_rst/library/data/datahandler2d.html b/_rst/library/data/datahandler2d.html new file mode 100644 index 0000000..58d5319 --- /dev/null +++ b/_rst/library/data/datahandler2d.html @@ -0,0 +1,262 @@ + + + + + + + fastvpinns.data.datahandler2d module — fastvpinns 1.0.0 documentation + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

fastvpinns.data.datahandler2d module

+
+
+class fastvpinns.data.datahandler2d.DataHandler2D(fespace, domain, dtype)[source]
+

Bases: DataHandler

+

This class is to handle data for 2D problems, convert them into tensors using custom tf functions. +It is responsible for all type conversions and data handling.

+
+

Note

+

All inputs to these functions are generally numpy arrays with dtype np.float64. +So we can either maintain the same dtype or convert them to tf.float32 ( for faster computation ).

+
+
+
Parameters:
+
    +
  • fespace (FESpace2D) – The FESpace2D object.

  • +
  • domain (Domain2D) – The Domain2D object.

  • +
  • shape_val_mat_list (list) – List of shape function values for each cell.

  • +
  • grad_x_mat_list (list) – List of shape function derivatives with respect to x for each cell.

  • +
  • grad_y_mat_list (list) – List of shape function derivatives with respect to y for each cell.

  • +
  • x_pde_list (list) – List of actual coordinates of the quadrature points for each cell.

  • +
  • forcing_function_list (list) – List of forcing function values for each cell.

  • +
  • dtype (tf.DType) – The tensorflow dtype to be used for all the tensors.

  • +
+
+
+
+
+get_bilinear_params_dict_as_tensors(function)[source]
+

Accepts a function from example file and converts all the values into tensors of the given dtype

+

Parameters: +- function (function): The function from the example file which returns the bilinear parameters dictionary

+

Returns: +- bilinear_params_dict (dict): The bilinear parameters dictionary with all the values converted to tensors

+
+
Parameters:
+

function (function) – The function from the example file which returns the bilinear parameters dictionary

+
+
Returns:
+

The bilinear parameters dictionary with all the values converted to tensors

+
+
Return type:
+

dict

+
+
+
+ +
+
+get_dirichlet_input()[source]
+

This function will return the input for the Dirichlet boundary data

+
+
Returns:
+

    +
  • input_dirichlet (tf.Tensor): The input for the Dirichlet boundary data

  • +
  • actual_dirichlet (tf.Tensor): The actual Dirichlet boundary data

  • +
+

+
+
+
+ +
+
+get_inverse_params(inverse_params_dict_function)[source]
+

Accepts a function from example file and converts all the values into tensors of the given dtype

+
+
Parameters:
+

inverse_params_dict_function (function) – The function from the example file which returns the inverse parameters dictionary

+
+
Returns:
+

The inverse parameters dictionary with all the values converted to tensors

+
+
Return type:
+

dict

+
+
+
+ +
+
+get_sensor_data(exact_sol, num_sensor_points, mesh_type, file_name=None)[source]
+

Accepts a function from example file and converts all the values into tensors of the given dtype

+
+
Parameters:
+
    +
  • exact_sol (function) – The function from the example file which returns the exact solution

  • +
  • num_sensor_points (int) – The number of sensor points to be generated

  • +
  • mesh_type (str) – The type of mesh to be used for sensor data generation

  • +
  • file_name (str, optional) – The name of the file to be used for external mesh generation, defaults to None

  • +
+
+
Returns:
+

The sensor points and sensor values as tensors

+
+
Return type:
+

tuple[tf.Tensor, tf.Tensor]

+
+
+
+ +
+
+get_test_points()[source]
+

Get the test points for the given domain.

+
+
Returns:
+

The test points for the given domain.

+
+
Return type:
+

tf.Tensor

+
+
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_rst/library/fe2d/fe2d_affine_transformation.html b/_rst/library/fe2d/fe2d_affine_transformation.html new file mode 100644 index 0000000..a719a1d --- /dev/null +++ b/_rst/library/fe2d/fe2d_affine_transformation.html @@ -0,0 +1,268 @@ + + + + + + + fastvpinns.FE.quad_affine module — fastvpinns 1.0.0 documentation + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

fastvpinns.FE.quad_affine module

+

file: quad_affine.py +description: This file defines the Quad Affine transformation of the reference element.

+
+

The implementation is referenced from the ParMooN project (File: QuadAffine.C).

+
+

authors: Thivin Anandh D +changelog: 30/Aug/2023 - Initial version +known_issues: None +dependencies: None specified.

+
+
+class fastvpinns.FE.quad_affine.QuadAffin(co_ordinates)[source]
+

Bases: FETransforamtion2D

+

Defines the Quad Affine transformation of the reference element.

+
+
Parameters:
+

co_ordinates (numpy.ndarray) – The coordinates of the reference element.

+
+
+
+
+get_jacobian(xi, eta)[source]
+

Returns the Jacobian of the transformation.

+
+
Parameters:
+
    +
  • xi (float) – The xi coordinate.

  • +
  • eta (float) – The eta coordinate.

  • +
+
+
Returns:
+

The Jacobian of the transformation.

+
+
Return type:
+

float

+
+
+
+ +
+
+get_orig_from_ref_derivative(ref_gradx, ref_grady, xi, eta)[source]
+

Returns the derivatives of the original coordinates with respect to the reference coordinates.

+
+
Parameters:
+
    +
  • ref_gradx (numpy.ndarray) – The reference gradient in the x-direction.

  • +
  • ref_grady (numpy.ndarray) – The reference gradient in the y-direction.

  • +
  • xi (float) – The xi coordinate.

  • +
  • eta (float) – The eta coordinate.

  • +
+
+
Returns:
+

The derivatives of the original coordinates with respect to the reference coordinates.

+
+
Return type:
+

tuple

+
+
+
+ +
+
+get_orig_from_ref_second_derivative(grad_xx_ref, grad_xy_ref, grad_yy_ref, xi, eta)[source]
+

Returns the second derivatives (xx, xy, yy) of the original coordinates with respect to the reference coordinates.

+
+
Parameters:
+
    +
  • grad_xx_ref (numpy.ndarray) – The reference second derivative in the xx-direction.

  • +
  • grad_xy_ref (numpy.ndarray) – The reference second derivative in the xy-direction.

  • +
  • grad_yy_ref (numpy.ndarray) – The reference second derivative in the yy-direction.

  • +
  • xi (float) – The xi coordinate.

  • +
  • eta (float) – The eta coordinate.

  • +
+
+
Returns:
+

The second derivatives (xx, xy, yy) of the original coordinates with respect to the reference coordinates.

+
+
Return type:
+

tuple

+
+
+
+ +
+
+get_original_from_ref(xi, eta)[source]
+

Returns the original coordinates from the reference coordinates.

+
+
Parameters:
+
    +
  • xi (float) – The xi coordinate.

  • +
  • eta (float) – The eta coordinate.

  • +
+
+
Returns:
+

numpy.ndarray +The original coordinates.

+
+
+
+ +
+
+set_cell()[source]
+

Set the cell coordinates, which will be used to calculate the Jacobian and actual values.

+
+
Parameters:
+

None – There are no parameters for this method.

+
+
Returns None:
+

This method does not return anything.

+
+
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_rst/library/fe2d/fe2d_basis_function.html b/_rst/library/fe2d/fe2d_basis_function.html new file mode 100644 index 0000000..57fb8c1 --- /dev/null +++ b/_rst/library/fe2d/fe2d_basis_function.html @@ -0,0 +1,420 @@ + + + + + + + fastvpinns.FE.basis_2d_QN_Jacobi module — fastvpinns 1.0.0 documentation + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

fastvpinns.FE.basis_2d_QN_Jacobi module

+

file: basis_2d_QN_Jacobi.py +description: This file contains the class Basis2DQNJacobi which is used

+
+

to define the basis functions for a Jacobi Polynomial. +Test functions and derivatives are inferred from the work by Ehsan Kharazmi et.al +(hp-VPINNs: Variational Physics-Informed Neural Networks With Domain Decomposition) +available at https://github.com/ehsankharazmi/hp-VPINNs/

+
+

authors: Thivin Anandh D +changelog: 30/Aug/2023 - Initial version +known_issues: None +dependencies: Requires scipy and numpy.

+
+
+class fastvpinns.FE.basis_2d_QN_Jacobi.Basis2DQNJacobi(num_shape_functions: int)[source]
+

Bases: BasisFunction2D

+

This class defines the basis functions for a 2D Q1 element.

+
+
+ddtest_fcn(n_test, x)[source]
+

Compute the x-derivatives of the test functions for a given number of test functions and x-coordinates.

+
+
Parameters:
+
    +
  • n_test (int) – Number of test functions.

  • +
  • x (array_like) – x-coordinates at which to evaluate the test functions.

  • +
+
+
Returns:
+

Values of the x-derivatives of the test functions.

+
+
Return type:
+

array_like

+
+
+
+ +
+
+djacobi(n, a, b, x, k: int)[source]
+

Evaluate the k-th derivative of the Jacobi polynomial of degree n with parameters a and b at the given points x.

+
+
Parameters:
+
    +
  • n (int) – Degree of the Jacobi polynomial.

  • +
  • a (float) – First parameter of the Jacobi polynomial.

  • +
  • b (float) – Second parameter of the Jacobi polynomial.

  • +
  • x (array_like) – Points at which to evaluate the Jacobi polynomial.

  • +
  • k (int) – Order of the derivative.

  • +
+
+
Returns:
+

Values of the k-th derivative of the Jacobi polynomial at the given points x.

+
+
Return type:
+

array_like

+
+
Raises:
+
    +
  • ValueError – If the derivative order is not 1 or 2.

  • +
  • ImportError – If the required module ‘jacobi’ is not found.

  • +
  • Exception – If an unknown error occurs during the computation.

  • +
+
+
+
+ +
+
+dtest_fcn(n_test, x)[source]
+

Compute the x-derivatives of the test functions for a given number of test functions and x-coordinates.

+
+
Parameters:
+
    +
  • n_test (int) – Number of test functions.

  • +
  • x (array_like) – x-coordinates at which to evaluate the test functions.

  • +
+
+
Returns:
+

Values of the x-derivatives of the test functions.

+
+
Return type:
+

array_like

+
+
+
+ +
+
+gradx(xi, eta)[source]
+

This method returns the x-derivatives of the basis functions at the given (xi, eta) coordinates.

+
+
Parameters:
+
    +
  • xi (array_like) – x-coordinates at which to evaluate the basis functions.

  • +
  • eta (array_like) – y-coordinates at which to evaluate the basis functions.

  • +
+
+
Returns:
+

Values of the x-derivatives of the basis functions.

+
+
Return type:
+

array_like

+
+
+
+ +
+
+gradxx(xi, eta)[source]
+

This method returns the xx-derivatives of the basis functions at the given (xi, eta) coordinates.

+
+
Parameters:
+
    +
  • xi (array_like) – x-coordinates at which to evaluate the basis functions.

  • +
  • eta (array_like) – y-coordinates at which to evaluate the basis functions.

  • +
+
+
Returns:
+

Values of the xx-derivatives of the basis functions.

+
+
Return type:
+

array_like

+
+
+
+ +
+
+gradxy(xi, eta)[source]
+

This method returns the xy-derivatives of the basis functions at the given (xi, eta) coordinates.

+
+
Parameters:
+
    +
  • xi (array_like) – x-coordinates at which to evaluate the basis functions.

  • +
  • eta (array_like) – y-coordinates at which to evaluate the basis functions.

  • +
+
+
Returns:
+

Values of the xy-derivatives of the basis functions.

+
+
Return type:
+

array_like

+
+
+
+ +
+
+grady(xi, eta)[source]
+

This method returns the y-derivatives of the basis functions at the given (xi, eta) coordinates.

+
+
Parameters:
+
    +
  • xi (array_like) – x-coordinates at which to evaluate the basis functions.

  • +
  • eta (array_like) – y-coordinates at which to evaluate the basis functions.

  • +
+
+
Returns:
+

Values of the y-derivatives of the basis functions.

+
+
Return type:
+

array_like

+
+
+
+ +
+
+gradyy(xi, eta)[source]
+

This method returns the yy-derivatives of the basis functions at the given (xi, eta) coordinates.

+
+
Parameters:
+
    +
  • xi (array_like) – x-coordinates at which to evaluate the basis functions.

  • +
  • eta (array_like) – y-coordinates at which to evaluate the basis functions.

  • +
+
+
Returns:
+

Values of the yy-derivatives of the basis functions.

+
+
Return type:
+

array_like

+
+
+
+ +
+
+jacobi_wrapper(n, a, b, x)[source]
+

Evaluate the Jacobi polynomial of degree n with parameters a and b at the given points x.

+
+
Parameters:
+
    +
  • n (int) – Degree of the Jacobi polynomial.

  • +
  • a (float) – First parameter of the Jacobi polynomial.

  • +
  • b (float) – Second parameter of the Jacobi polynomial.

  • +
  • x (array_like) – Points at which to evaluate the Jacobi polynomial.

  • +
+
+
Returns:
+

Values of the Jacobi polynomial at the given points x.

+
+
Return type:
+

array_like

+
+
+
+ +
+
+test_fcnx(n_test, x)[source]
+

Compute the x-component of the test functions for a given number of test functions and x-coordinates.

+
+
Parameters:
+
    +
  • n_test (int) – Number of test functions.

  • +
  • x (array_like) – x-coordinates at which to evaluate the test functions.

  • +
+
+
Returns:
+

Values of the x-component of the test functions.

+
+
Return type:
+

array_like

+
+
+
+ +
+
+test_fcny(n_test, y)[source]
+

Compute the y-component of the test functions for a given number of test functions and y-coordinates.

+
+
Parameters:
+
    +
  • n_test (int) – Number of test functions.

  • +
  • y (array_like) – y-coordinates at which to evaluate the test functions.

  • +
+
+
Returns:
+

Values of the y-component of the test functions.

+
+
Return type:
+

array_like

+
+
+
+ +
+
+value(xi, eta)[source]
+

This method returns the values of the basis functions at the given (xi, eta) coordinates.

+
+
Parameters:
+
    +
  • xi (array_like) – x-coordinates at which to evaluate the basis functions.

  • +
  • eta (array_like) – y-coordinates at which to evaluate the basis functions.

  • +
+
+
Returns:
+

Values of the basis functions.

+
+
Return type:
+

array_like

+
+
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_rst/library/fe2d/fe2d_bilinear_transformation.html b/_rst/library/fe2d/fe2d_bilinear_transformation.html new file mode 100644 index 0000000..55b49d7 --- /dev/null +++ b/_rst/library/fe2d/fe2d_bilinear_transformation.html @@ -0,0 +1,273 @@ + + + + + + + fastvpinns.FE.quad_bilinear module — fastvpinns 1.0.0 documentation + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

fastvpinns.FE.quad_bilinear module

+

file: quad_bilinear.py +description: This file defines the Quad Affine transformation of the reference element.

+
+

The implementation is referenced from the ParMooN project (File: QuadBilineare.C).

+
+

authors: Thivin Anandh D +changelog: 30/Aug/2023 - Initial version +known_issues: Second derivative Calculations are not implemented as of now. +dependencies: None specified.

+
+
+class fastvpinns.FE.quad_bilinear.QuadBilinear(co_ordinates)[source]
+

Bases: FETransforamtion2D

+

Defines the Quad Bilinear transformation of the reference element.

+
+
Parameters:
+

co_ordinates (numpy.ndarray) – The coordinates of the reference element.

+
+
+
+
+get_jacobian(xi, eta)[source]
+

This method returns the Jacobian of the transformation.

+
+
Parameters:
+
    +
  • xi (float) – The xi coordinate in the reference element.

  • +
  • eta (float) – The eta coordinate in the reference element.

  • +
+
+
Returns:
+

The Jacobian of the transformation at the given reference coordinates.

+
+
Return type:
+

float

+
+
+
+ +
+
+get_orig_from_ref_derivative(ref_gradx, ref_grady, xi, eta)[source]
+

This method returns the derivatives of the original coordinates with respect to the reference coordinates.

+
+
Parameters:
+
    +
  • ref_gradx (numpy.ndarray) – The gradient of the xi coordinate in the reference element.

  • +
  • ref_grady (numpy.ndarray) – The gradient of the eta coordinate in the reference element.

  • +
  • xi (float) – The xi coordinate in the reference element.

  • +
  • eta (float) – The eta coordinate in the reference element.

  • +
+
+
Returns:
+

The derivatives of the original coordinates [x, y] with respect to the reference coordinates.

+
+
Return type:
+

numpy.ndarray

+
+
+
+ +
+
+get_orig_from_ref_second_derivative(grad_xx_ref, grad_xy_ref, grad_yy_ref, xi, eta)[source]
+

This method returns the second derivatives of the original coordinates with respect to the reference coordinates.

+
+
Parameters:
+
    +
  • grad_xx_ref (numpy.ndarray) – The second derivative of the xi coordinate in the reference element.

  • +
  • grad_xy_ref (numpy.ndarray) – The mixed second derivative of the xi and eta coordinates in the reference element.

  • +
  • grad_yy_ref (numpy.ndarray) – The second derivative of the eta coordinate in the reference element.

  • +
  • xi (float) – The xi coordinate in the reference element.

  • +
  • eta (float) – The eta coordinate in the reference element.

  • +
+
+
Returns:
+

The second derivatives of the original coordinates [xx, xy, yy] with respect to the reference coordinates.

+
+
Return type:
+

numpy.ndarray

+
+
+
+ +
+
+get_original_from_ref(xi, eta)[source]
+

This method returns the original coordinates from the reference coordinates.

+
+
Parameters:
+
    +
  • xi (float) – The xi coordinate in the reference element.

  • +
  • eta (float) – The eta coordinate in the reference element.

  • +
+
+
Returns:
+

The original coordinates [x, y] corresponding to the given reference coordinates.

+
+
Return type:
+

numpy.ndarray

+
+
+
+ +
+
+set_cell()[source]
+

Set the cell coordinates, which will be used as intermediate values to calculate the Jacobian and actual values.

+
+
Parameters:
+

None

+
+
Returns:
+

None

+
+
Return type:
+

None

+
+
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_rst/library/fe2d/fe2d_fe2d_cell.html b/_rst/library/fe2d/fe2d_fe2d_cell.html new file mode 100644 index 0000000..0a4dccd --- /dev/null +++ b/_rst/library/fe2d/fe2d_fe2d_cell.html @@ -0,0 +1,259 @@ + + + + + + + fastvpinns.FE.FE2D_Cell module — fastvpinns 1.0.0 documentation + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

fastvpinns.FE.FE2D_Cell module

+
+
+class fastvpinns.FE.FE2D_Cell.FE2D_Cell(cell_coordinates: ndarray, cell_type: str, fe_order: int, fe_type: str, quad_order: int, quad_type: str, fe_transformation_type: str, forcing_function)[source]
+

Bases: object

+

This class is used to Store the FE Values, Such as Coordinates, Basis Functions, Quadrature Rules, etc. for a given cell.

+
+
+assign_basis_function() BasisFunction2D[source]
+

Assigns the basis function class based on the cell type and the FE order.

+
+
Returns:
+

An instance of the BasisFunction2D class.

+
+
+
+ +
+
+assign_basis_values_at_quadrature_points() None[source]
+

Assigns the basis function values at the quadrature points.

+

This method calculates the values of the basis functions and their gradients at the quadrature points. +The basis function values are stored in self.basis_at_quad, while the gradients are stored in +self.basis_gradx_at_quad, self.basis_grady_at_quad, self.basis_gradxy_at_quad, +self.basis_gradxx_at_quad, and self.basis_gradyy_at_quad.

+

The basis function values are of size N_basis_functions x N_quad_points.

+
+
Returns:
+

None

+
+
+
+ +
+
+assign_fe_transformation() None[source]
+

Assigns the FE Transformation class based on the cell type and the FE order.

+

This method assigns the appropriate FE Transformation class based on the cell type and the FE order. +It sets the cell coordinates for the FE Transformation and obtains the Jacobian of the transformation.

+
+
Returns:
+

None

+
+
+
+ +
+
+assign_forcing_term(forcing_function) None[source]
+

Assigns the forcing function values at the quadrature points.

+

This function computes the values of the forcing function at the quadrature points +and assigns them to the forcing_at_quad attribute of the FE2D_Cell object.

+
+
Parameters:
+

forcing_function (callable) – The forcing function that takes the coordinates (x, y) +as input and returns the value of the forcing function at those coordinates.

+
+
Returns:
+

None

+
+
+

Notes

+
    +
  • The final shape of forcing_at_quad will be N_shape_functions x 1.

  • +
  • This function is for backward compatibility with old code and currently assigns +the values as zeros. The actual calculation is performed in the fespace class.

  • +
+
+ +
+
+assign_quad_weights_and_jacobian() None[source]
+

Assigns the quadrature weights and the Jacobian of the transformation.

+

This method calculates and assigns the quadrature weights and the Jacobian of the transformation +for the current cell. The quadrature weights are multiplied by the flattened Jacobian array +and stored in the mult attribute of the class.

+
+
Returns:
+

None

+
+
+
+ +
+
+assign_quadrature() None[source]
+

Assigns the quadrature points and weights based on the cell type and the quadrature order.

+
+
Returns:
+

None

+
+
+
+ +
+
+assign_quadrature_coordinates() None[source]
+

Assigns the actual coordinates of the quadrature points.

+

This method calculates the actual coordinates of the quadrature points based on the given Xi and Eta values. +The Xi and Eta values are obtained from the quad_xi and quad_eta attributes of the class. +The calculated coordinates are stored in the quad_actual_coordinates attribute as a NumPy array.

+
+
Returns:
+

None

+
+
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_rst/library/fe2d/fe2d_fe2d_setup.html b/_rst/library/fe2d/fe2d_fe2d_setup.html new file mode 100644 index 0000000..614b05c --- /dev/null +++ b/_rst/library/fe2d/fe2d_fe2d_setup.html @@ -0,0 +1,214 @@ + + + + + + + fastvpinns.FE.fe2d_setup_main module — fastvpinns 1.0.0 documentation + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

fastvpinns.FE.fe2d_setup_main module

+
+
+class fastvpinns.FE.fe2d_setup_main.FE2DSetupMain(cell_type: str, fe_order: int, fe_type: str, quad_order: int, quad_type: str)[source]
+

Bases: object

+

This class is used to setup the FE2D and quadrature rule for a given cell based on the given mesh and the degree of the basis functions.

+
+
+assign_basis_function() BasisFunction2D[source]
+

Assigns the basis function based on the cell type and the fe_order.

+
+
Returns:
+

An instance of the BasisFunction2D class representing the assigned basis function.

+
+
Return type:
+

BasisFunction2D

+
+
Raises:
+

ValueError – If the fe_order is invalid.

+
+
+
+ +
+
+assign_fe_transformation(fe_transformation_type, cell_coordinates) FETransforamtion2D[source]
+

Assigns the FE transformation based on the cell type.

+
+
Parameters:
+
    +
  • fe_transformation_type (str) – The type of FE transformation.

  • +
  • cell_coordinates (list) – The coordinates of the cell.

  • +
+
+
Returns:
+

The FE transformation object.

+
+
Return type:
+

FETransforamtion2D

+
+
Raises:
+

ValueError – If the cell type or FE transformation type is invalid.

+
+
+
+ +
+
+assign_quadrature_rules()[source]
+

Assigns the quadrature rule based on the quad_order.

+
+
Returns:
+

A tuple containing the weights, xi, and eta values of the quadrature rule.

+
+
Return type:
+

tuple

+
+
Raises:
+

ValueError – If the quad_order is invalid or the cell_type is invalid.

+
+
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_rst/library/fe2d/fe2d_fespace2d.html b/_rst/library/fe2d/fe2d_fespace2d.html new file mode 100644 index 0000000..1bed563 --- /dev/null +++ b/_rst/library/fe2d/fe2d_fespace2d.html @@ -0,0 +1,537 @@ + + + + + + + fastvpinns.FE.fespace2d module — fastvpinns 1.0.0 documentation + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

fastvpinns.FE.fespace2d module

+

file: fespace2d.py +description: This file contains the main class that holds the information of all the

+
+

Finite Element (FE) spaces of all the cells within the given mesh.

+
+

authors: Thivin Anandh D +changelog: 30/Aug/2023 - Initial version +known_issues: None +dependencies: None specified.

+
+
+class fastvpinns.FE.fespace2d.Fespace2D(mesh, cells, boundary_points, cell_type: str, fe_order: int, fe_type: str, quad_order: int, quad_type: str, fe_transformation_type: str, bound_function_dict: dict, bound_condition_dict: dict, forcing_function, output_path: str, generate_mesh_plot: bool = False)[source]
+

Bases: Fespace

+

Represents a finite element space in 2D.

+
+
Parameters:
+
    +
  • mesh (Mesh) – The mesh object.

  • +
  • cells (ndarray) – The array of cell indices.

  • +
  • boundary_points (dict) – The dictionary of boundary points.

  • +
  • cell_type (str) – The type of cell.

  • +
  • fe_order (int) – The order of the finite element.

  • +
  • fe_type (str) – The type of finite element.

  • +
  • quad_order (int) – The order of the quadrature.

  • +
  • quad_type (str) – The type of quadrature.

  • +
  • fe_transformation_type (str) – The type of finite element transformation.

  • +
  • bound_function_dict (dict) – The dictionary of boundary functions.

  • +
  • bound_condition_dict (dict) – The dictionary of boundary conditions.

  • +
  • forcing_function (function) – The forcing function.

  • +
  • output_path (str) – The output path.

  • +
  • generate_mesh_plot (bool, optional) – Whether to generate a plot of the mesh. Defaults to False.

  • +
+
+
+
+
+generate_dirichlet_boundary_data() ndarray[source]
+

Generate Dirichlet boundary data.

+

This function returns the boundary points and their corresponding values.

+
+
Returns:
+

A tuple containing two arrays: +- The first array contains the boundary points as numpy arrays. +- The second array contains the values of the boundary points as numpy arrays.

+
+
Return type:
+

Tuple[np.ndarray, np.ndarray]

+
+
+
+ +
+
+generate_dirichlet_boundary_data_vector(component) ndarray[source]
+

Generate the boundary data vector for the Dirichlet boundary condition.

+

This function returns the boundary points and their corresponding values for a specific component.

+
+
Parameters:
+

component (int) – The component for which the boundary data vector is generated.

+
+
Returns:
+

The boundary points and their values as numpy arrays.

+
+
Return type:
+

tuple(numpy.ndarray, numpy.ndarray)

+
+
+
+ +
+
+generate_plot(output_path) None[source]
+

Generate a plot of the mesh.

+
+
Parameters:
+

output_path (str) – The path to save the generated plot.

+
+
+
+ +
+
+get_forcing_function_values(cell_index) ndarray[source]
+

Get the forcing function values at the quadrature points.

+
+
Parameters:
+

cell_index (int) – The index of the cell.

+
+
Returns:
+

The forcing function values at the quadrature points.

+
+
Return type:
+

np.ndarray

+
+
Raises:
+

ValueError – If cell_index is greater than the number of cells.

+
+
+

This function computes the forcing function values at the quadrature points for a given cell. +It loops over all the basis functions and computes the integral using the actual coordinates +and the basis functions at the quadrature points. The resulting values are stored in the +forcing_at_quad attribute of the corresponding fe_cell object.

+

Note: The forcing function is evaluated using the forcing_function method of the fe_cell +object.

+
+
Example usage:
>>> fespace = FESpace2D()
+>>> cell_index = 0
+>>> forcing_values = fespace.get_forcing_function_values(cell_index)
+
+
+
+
+
+ +
+
+get_forcing_function_values_vector(cell_index, component) ndarray[source]
+

This function will return the forcing function values at the quadrature points +based on the Component of the RHS Needed, for vector valued problems

+
+
Parameters:
+
    +
  • cell_index (int) – The index of the cell

  • +
  • component (int) – The component of the RHS needed

  • +
+
+
Returns:
+

The forcing function values at the quadrature points

+
+
Return type:
+

np.ndarray

+
+
Raises:
+

ValueError – If cell_index is greater than the number of cells

+
+
+
+ +
+
+get_quadrature_actual_coordinates(cell_index) ndarray[source]
+

Get the actual coordinates of the quadrature points for a given cell.

+
+
Parameters:
+

cell_index (int) – The index of the cell.

+
+
Returns:
+

An array containing the actual coordinates of the quadrature points.

+
+
Return type:
+

np.ndarray

+
+
Raises:
+

ValueError – If the cell_index is greater than the number of cells.

+
+
Example:
+

+
+
>>> fespace = FESpace2D()
+>>> fespace.get_quadrature_actual_coordinates(0)
+array([[0.1, 0.2],
+        [0.3, 0.4],
+        [0.5, 0.6]])
+
+
+
+ +
+
+get_quadrature_weights(cell_index) ndarray[source]
+

Return the quadrature weights for a given cell.

+
+
Parameters:
+

cell_index (int) – The index of the cell for which the quadrature weights are needed.

+
+
Returns:
+

The quadrature weights for the given cell of dimension (N_Quad_Points, 1).

+
+
Return type:
+

np.ndarray

+
+
Raises:
+

ValueError – If cell_index is greater than the number of cells.

+
+
+

Notes

+

This function returns the quadrature weights associated with a specific cell. +The quadrature weights are stored in the mult attribute of the fe_cell object.

+

Example

+
>>> fespace = FESpace2D()
+>>> weights = fespace.get_quadrature_weights(0)
+>>> print(weights)
+[0.1, 0.2, 0.3, 0.4]
+
+
+
+
Parameters:
+

cell_index (int) – The index of the cell for which the quadrature weights are needed.

+
+
Returns:
+

The quadrature weights for the given cell.

+
+
Return type:
+

np.ndarray

+
+
Raises:
+

ValueError – If cell_index is greater than the number of cells.

+
+
+
+ +
+
+get_sensor_data(exact_solution, num_points)[source]
+

Obtain sensor data (actual solution) at random points.

+

This method is used in the inverse problem to obtain the sensor data at random points within the domain. +Currently, it only works for problems with an analytical solution. +Methodologies to obtain sensor data for problems from a file are not implemented yet. +It is also not implemented for external or complex meshes.

+
+
Parameters:
+
    +
  • exact_solution (function) – A function that computes the exact solution at a given point.

  • +
  • num_points (int) – The number of random points to generate.

  • +
+
+
Returns:
+

A tuple containing the generated points and the exact solution at those points.

+
+
Return type:
+

tuple(numpy.ndarray, numpy.ndarray)

+
+
+
+ +
+
+get_sensor_data_external(exact_sol, num_points, file_name)[source]
+

This method is used to obtain the sensor data from an external file.

+
+
Parameters:
+
    +
  • exact_sol (array-like) – The exact solution values.

  • +
  • num_points (int) – The number of points to sample from the data.

  • +
  • file_name (str) – The path to the file containing the sensor data.

  • +
+
+
Returns:
+

A tuple containing two arrays: +- points (ndarray): The sampled points from the data. +- exact_sol (ndarray): The corresponding exact solution values.

+
+
Return type:
+

tuple

+
+
+
+ +
+
+get_shape_function_grad_x(cell_index) ndarray[source]
+

Get the gradient of the shape function with respect to the x-coordinate.

+
+
Parameters:
+

cell_index (int) – The index of the cell.

+
+
Returns:
+

An array containing the gradient of the shape function with respect to the x-coordinate.

+
+
Return type:
+

np.ndarray

+
+
Raises:
+

ValueError – If the cell_index is greater than the number of cells.

+
+
+

This function returns the actual values of the gradient of the shape function on a given cell.

+
+ +
+
+get_shape_function_grad_x_ref(cell_index) ndarray[source]
+

Get the gradient of the shape function with respect to the x-coordinate on the reference element.

+
+
Parameters:
+

cell_index (int) – The index of the cell.

+
+
Returns:
+

An array containing the gradient of the shape function with respect to the x-coordinate.

+
+
Return type:
+

np.ndarray

+
+
Raises:
+

ValueError – If the cell_index is greater than the number of cells.

+
+
+
+ +
+
+get_shape_function_grad_y(cell_index) ndarray[source]
+

Get the gradient of the shape function with respect to y at the given cell index.

+
+
Parameters:
+

cell_index (int) – The index of the cell.

+
+
Returns:
+

The gradient of the shape function with respect to y.

+
+
Return type:
+

np.ndarray

+
+
Raises:
+

ValueError – If the cell_index is greater than the total number of cells.

+
+
+
+ +
+
+get_shape_function_grad_y_ref(cell_index)[source]
+

Get the gradient of the shape function with respect to y at the reference element.

+
+
Parameters:
+

cell_index (int) – The index of the cell.

+
+
Returns:
+

The gradient of the shape function with respect to y at the reference element.

+
+
Return type:
+

np.ndarray

+
+
Raises:
+

ValueError – If cell_index is greater than the number of cells.

+
+
+

This function returns the gradient of the shape function with respect to y at the reference element +for a given cell. The shape function gradient values are stored in the basis_grady_at_quad_ref array +of the corresponding finite element cell. The cell_index parameter specifies the index of the cell +for which the shape function gradient is required. If the cell_index is greater than the total number +of cells, a ValueError is raised.

+
+

Note

+

The returned gradient values are copied from the basis_grady_at_quad_ref array to ensure immutability.

+
+
+ +
+
+get_shape_function_val(cell_index) ndarray[source]
+

Get the actual values of the shape functions on a given cell.

+
+
Parameters:
+

cell_index (int) – The index of the cell.

+
+
Returns:
+

An array containing the actual values of the shape functions.

+
+
Return type:
+

np.ndarray

+
+
Raises:
+

ValueError – If the cell_index is greater than the number of cells.

+
+
+
+ +
+
+set_finite_elements() None[source]
+

Assigns the finite elements to each cell.

+

This method initializes the finite element objects for each cell in the mesh. +It creates an instance of the FE2D_Cell class for each cell, passing the necessary parameters. +The finite element objects store information about the basis functions, gradients, Jacobians, +quadrature points, weights, actual coordinates, and forcing functions associated with each cell.

+

After initializing the finite element objects, this method prints the shape details of various matrices +and updates the total number of degrees of freedom (dofs) for the entire mesh.

+
+
Returns:
+

None

+
+
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_rst/library/fe2d/fe2d_jacobi.html b/_rst/library/fe2d/fe2d_jacobi.html new file mode 100644 index 0000000..68bdac3 --- /dev/null +++ b/_rst/library/fe2d/fe2d_jacobi.html @@ -0,0 +1,420 @@ + + + + + + + fastvpinns.FE.basis_2d_QN_Jacobi module — fastvpinns 1.0.0 documentation + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

fastvpinns.FE.basis_2d_QN_Jacobi module

+

file: basis_2d_QN_Jacobi.py +description: This file contains the class Basis2DQNJacobi which is used

+
+

to define the basis functions for a Jacobi Polynomial. +Test functions and derivatives are inferred from the work by Ehsan Kharazmi et.al +(hp-VPINNs: Variational Physics-Informed Neural Networks With Domain Decomposition) +available at https://github.com/ehsankharazmi/hp-VPINNs/

+
+

authors: Thivin Anandh D +changelog: 30/Aug/2023 - Initial version +known_issues: None +dependencies: Requires scipy and numpy.

+
+
+class fastvpinns.FE.basis_2d_QN_Jacobi.Basis2DQNJacobi(num_shape_functions: int)[source]
+

Bases: BasisFunction2D

+

This class defines the basis functions for a 2D Q1 element.

+
+
+ddtest_fcn(n_test, x)[source]
+

Compute the x-derivatives of the test functions for a given number of test functions and x-coordinates.

+
+
Parameters:
+
    +
  • n_test (int) – Number of test functions.

  • +
  • x (array_like) – x-coordinates at which to evaluate the test functions.

  • +
+
+
Returns:
+

Values of the x-derivatives of the test functions.

+
+
Return type:
+

array_like

+
+
+
+ +
+
+djacobi(n, a, b, x, k: int)[source]
+

Evaluate the k-th derivative of the Jacobi polynomial of degree n with parameters a and b at the given points x.

+
+
Parameters:
+
    +
  • n (int) – Degree of the Jacobi polynomial.

  • +
  • a (float) – First parameter of the Jacobi polynomial.

  • +
  • b (float) – Second parameter of the Jacobi polynomial.

  • +
  • x (array_like) – Points at which to evaluate the Jacobi polynomial.

  • +
  • k (int) – Order of the derivative.

  • +
+
+
Returns:
+

Values of the k-th derivative of the Jacobi polynomial at the given points x.

+
+
Return type:
+

array_like

+
+
Raises:
+
    +
  • ValueError – If the derivative order is not 1 or 2.

  • +
  • ImportError – If the required module ‘jacobi’ is not found.

  • +
  • Exception – If an unknown error occurs during the computation.

  • +
+
+
+
+ +
+
+dtest_fcn(n_test, x)[source]
+

Compute the x-derivatives of the test functions for a given number of test functions and x-coordinates.

+
+
Parameters:
+
    +
  • n_test (int) – Number of test functions.

  • +
  • x (array_like) – x-coordinates at which to evaluate the test functions.

  • +
+
+
Returns:
+

Values of the x-derivatives of the test functions.

+
+
Return type:
+

array_like

+
+
+
+ +
+
+gradx(xi, eta)[source]
+

This method returns the x-derivatives of the basis functions at the given (xi, eta) coordinates.

+
+
Parameters:
+
    +
  • xi (array_like) – x-coordinates at which to evaluate the basis functions.

  • +
  • eta (array_like) – y-coordinates at which to evaluate the basis functions.

  • +
+
+
Returns:
+

Values of the x-derivatives of the basis functions.

+
+
Return type:
+

array_like

+
+
+
+ +
+
+gradxx(xi, eta)[source]
+

This method returns the xx-derivatives of the basis functions at the given (xi, eta) coordinates.

+
+
Parameters:
+
    +
  • xi (array_like) – x-coordinates at which to evaluate the basis functions.

  • +
  • eta (array_like) – y-coordinates at which to evaluate the basis functions.

  • +
+
+
Returns:
+

Values of the xx-derivatives of the basis functions.

+
+
Return type:
+

array_like

+
+
+
+ +
+
+gradxy(xi, eta)[source]
+

This method returns the xy-derivatives of the basis functions at the given (xi, eta) coordinates.

+
+
Parameters:
+
    +
  • xi (array_like) – x-coordinates at which to evaluate the basis functions.

  • +
  • eta (array_like) – y-coordinates at which to evaluate the basis functions.

  • +
+
+
Returns:
+

Values of the xy-derivatives of the basis functions.

+
+
Return type:
+

array_like

+
+
+
+ +
+
+grady(xi, eta)[source]
+

This method returns the y-derivatives of the basis functions at the given (xi, eta) coordinates.

+
+
Parameters:
+
    +
  • xi (array_like) – x-coordinates at which to evaluate the basis functions.

  • +
  • eta (array_like) – y-coordinates at which to evaluate the basis functions.

  • +
+
+
Returns:
+

Values of the y-derivatives of the basis functions.

+
+
Return type:
+

array_like

+
+
+
+ +
+
+gradyy(xi, eta)[source]
+

This method returns the yy-derivatives of the basis functions at the given (xi, eta) coordinates.

+
+
Parameters:
+
    +
  • xi (array_like) – x-coordinates at which to evaluate the basis functions.

  • +
  • eta (array_like) – y-coordinates at which to evaluate the basis functions.

  • +
+
+
Returns:
+

Values of the yy-derivatives of the basis functions.

+
+
Return type:
+

array_like

+
+
+
+ +
+
+jacobi_wrapper(n, a, b, x)[source]
+

Evaluate the Jacobi polynomial of degree n with parameters a and b at the given points x.

+
+
Parameters:
+
    +
  • n (int) – Degree of the Jacobi polynomial.

  • +
  • a (float) – First parameter of the Jacobi polynomial.

  • +
  • b (float) – Second parameter of the Jacobi polynomial.

  • +
  • x (array_like) – Points at which to evaluate the Jacobi polynomial.

  • +
+
+
Returns:
+

Values of the Jacobi polynomial at the given points x.

+
+
Return type:
+

array_like

+
+
+
+ +
+
+test_fcnx(n_test, x)[source]
+

Compute the x-component of the test functions for a given number of test functions and x-coordinates.

+
+
Parameters:
+
    +
  • n_test (int) – Number of test functions.

  • +
  • x (array_like) – x-coordinates at which to evaluate the test functions.

  • +
+
+
Returns:
+

Values of the x-component of the test functions.

+
+
Return type:
+

array_like

+
+
+
+ +
+
+test_fcny(n_test, y)[source]
+

Compute the y-component of the test functions for a given number of test functions and y-coordinates.

+
+
Parameters:
+
    +
  • n_test (int) – Number of test functions.

  • +
  • y (array_like) – y-coordinates at which to evaluate the test functions.

  • +
+
+
Returns:
+

Values of the y-component of the test functions.

+
+
Return type:
+

array_like

+
+
+
+ +
+
+value(xi, eta)[source]
+

This method returns the values of the basis functions at the given (xi, eta) coordinates.

+
+
Parameters:
+
    +
  • xi (array_like) – x-coordinates at which to evaluate the basis functions.

  • +
  • eta (array_like) – y-coordinates at which to evaluate the basis functions.

  • +
+
+
Returns:
+

Values of the basis functions.

+
+
Return type:
+

array_like

+
+
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_rst/library/fe2d/fe2d_quadratureformulas.html b/_rst/library/fe2d/fe2d_quadratureformulas.html new file mode 100644 index 0000000..83b00f0 --- /dev/null +++ b/_rst/library/fe2d/fe2d_quadratureformulas.html @@ -0,0 +1,198 @@ + + + + + + + fastvpinns.FE.quadratureformulas module — fastvpinns 1.0.0 documentation + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

fastvpinns.FE.quadratureformulas module

+

file: quadratureformulas.py +description: Abstract class for all quadrature formulas +authors: Thivin Anandh D +changelog: Not specified +known_issues: None +dependencies: numpy, scipy

+
+
+class fastvpinns.FE.quadratureformulas.Quadratureformulas(quad_order: int, quad_type: str, num_quad_points: int)[source]
+

Bases: object

+

Defines the Quadrature Formulas for the 2D Quadrilateral elements.

+
+
Parameters:
+
    +
  • quad_order (int) – The order of the quadrature.

  • +
  • quad_type (str) – The type of the quadrature.

  • +
+
+
+
+
+abstract get_num_quad_points()[source]
+

Returns the number of quadrature points.

+
+
Returns:
+

The number of quadrature points.

+
+
Return type:
+

int

+
+
+
+ +
+
+abstract get_quad_values()[source]
+

Returns the quadrature weights, xi and eta values.

+
+
Returns:
+

A tuple containing the quadrature weights, xi values, and eta values.

+
+
Return type:
+

tuple

+
+
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_rst/library/fe2d/fe2d_quadratureformulas2d.html b/_rst/library/fe2d/fe2d_quadratureformulas2d.html new file mode 100644 index 0000000..01e1ece --- /dev/null +++ b/_rst/library/fe2d/fe2d_quadratureformulas2d.html @@ -0,0 +1,202 @@ + + + + + + + fastvpinns.FE.quadratureformulas_quad2d module — fastvpinns 1.0.0 documentation + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

fastvpinns.FE.quadratureformulas_quad2d module

+

file: quadratureformulas_quad2d.py +description: This file defines the Quadrature Formulas for the 2D Quadrilateral elements.

+
+

It supports both Gauss-Legendre and Gauss-Jacobi quadrature types. +The quadrature points and weights are calculated based on the specified quadrature order and type.

+
+

authors: Not specified +changelog: Not specified +known_issues: None +dependencies: numpy, scipy

+
+
+class fastvpinns.FE.quadratureformulas_quad2d.Quadratureformulas_Quad2D(quad_order: int, quad_type: str)[source]
+

Bases: Quadratureformulas

+

Defines the Quadrature Formulas for the 2D Quadrilateral elements.

+
+
Parameters:
+
    +
  • quad_order (int) – The order of the quadrature.

  • +
  • quad_type (str) – The type of the quadrature.

  • +
+
+
+
+
+get_num_quad_points()[source]
+

Returns the number of quadrature points.

+
+
Returns:
+

The number of quadrature points.

+
+
Return type:
+

int

+
+
+
+ +
+
+get_quad_values()[source]
+

Returns the quadrature weights, xi and eta values.

+
+
Returns:
+

A tuple containing the quadrature weights, xi values, and eta values.

+
+
Return type:
+

tuple

+
+
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_rst/library/fe2d/fe2d_transformation.html b/_rst/library/fe2d/fe2d_transformation.html new file mode 100644 index 0000000..c2fda30 --- /dev/null +++ b/_rst/library/fe2d/fe2d_transformation.html @@ -0,0 +1,208 @@ + + + + + + + fastvpinns.FE.fe_transformation_2d module — fastvpinns 1.0.0 documentation + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

fastvpinns.FE.fe_transformation_2d module

+
+
+class fastvpinns.FE.fe_transformation_2d.FETransforamtion2D[source]
+

Bases: object

+

This class represents a 2D finite element transformation.

+
+
+abstract get_jacobian(xi, eta)[source]
+

This method returns the Jacobian of the transformation.

+
+
Parameters:
+
    +
  • xi (float) – The xi coordinate.

  • +
  • eta (float) – The eta coordinate.

  • +
+
+
Returns:
+

The Jacobian matrix.

+
+
Return type:
+

numpy.ndarray

+
+
+
+ +
+
+abstract get_original_from_ref(xi, eta)[source]
+

This method returns the original coordinates from the reference coordinates.

+
+
Parameters:
+
    +
  • xi (float) – The xi value of the reference coordinates.

  • +
  • eta (float) – The eta value of the reference coordinates.

  • +
+
+
Returns:
+

The original coordinates corresponding to the given reference coordinates.

+
+
Return type:
+

tuple

+
+
+
+ +
+
+abstract set_cell()[source]
+

Set the cell coordinates, which will be used to calculate the Jacobian and actual values.

+
+
Returns:
+

None

+
+
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_rst/library/fe2d/fespace.html b/_rst/library/fe2d/fespace.html new file mode 100644 index 0000000..bf445f1 --- /dev/null +++ b/_rst/library/fe2d/fespace.html @@ -0,0 +1,395 @@ + + + + + + + fastvpinns.FE.fespace module — fastvpinns 1.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

fastvpinns.FE.fespace module

+

file: fespace.py +description: Abstract class for the FEspace Routines +authors: Thivin Anandh D +changelog: 03-May-2024 +known_issues: None +dependencies: None specified.

+
+
+class fastvpinns.FE.fespace.Fespace(mesh, cells, boundary_points, cell_type: str, fe_order: int, fe_type: str, quad_order: int, quad_type: str, fe_transformation_type: str, bound_function_dict: dict, bound_condition_dict: dict, forcing_function, output_path: str)[source]
+

Bases: object

+

Represents a finite element space.

+
+
Parameters:
+
    +
  • mesh (Mesh) – The mesh object.

  • +
  • cells (ndarray) – The array of cell indices.

  • +
  • boundary_points (dict) – The dictionary of boundary points.

  • +
  • cell_type (str) – The type of cell.

  • +
  • fe_order (int) – The order of the finite element.

  • +
  • fe_type (str) – The type of finite element.

  • +
  • quad_order (int) – The order of the quadrature.

  • +
  • quad_type (str) – The type of quadrature.

  • +
  • fe_transformation_type (str) – The type of finite element transformation.

  • +
  • bound_function_dict (dict) – The dictionary of boundary functions.

  • +
  • bound_condition_dict (dict) – The dictionary of boundary conditions.

  • +
  • forcing_function (function) – The forcing function.

  • +
  • output_path (str) – The output path.

  • +
  • generate_mesh_plot (bool, optional) – Whether to generate a plot of the mesh. Defaults to False.

  • +
+
+
+
+
+abstract generate_dirichlet_boundary_data() ndarray[source]
+

Generate Dirichlet boundary data.

+

This function returns the boundary points and their corresponding values.

+
+
Returns:
+

A tuple containing two arrays: +- The first array contains the boundary points as numpy arrays. +- The second array contains the values of the boundary points as numpy arrays.

+
+
Return type:
+

Tuple[np.ndarray, np.ndarray]

+
+
+
+ +
+
+abstract get_forcing_function_values(cell_index) ndarray[source]
+

Get the forcing function values at the quadrature points.

+
+
Parameters:
+

cell_index (int) – The index of the cell.

+
+
Returns:
+

The forcing function values at the quadrature points.

+
+
Return type:
+

np.ndarray

+
+
Raises:
+

ValueError – If cell_index is greater than the number of cells.

+
+
+

This function computes the forcing function values at the quadrature points for a given cell. +It loops over all the basis functions and computes the integral using the actual coordinates +and the basis functions at the quadrature points. The resulting values are stored in the +forcing_at_quad attribute of the corresponding fe_cell object.

+

Note: The forcing function is evaluated using the forcing_function method of the fe_cell +object.

+
+ +
+
+abstract get_quadrature_actual_coordinates(cell_index) ndarray[source]
+

Get the actual coordinates of the quadrature points for a given cell.

+
+
Parameters:
+

cell_index (int) – The index of the cell.

+
+
Returns:
+

An array containing the actual coordinates of the quadrature points.

+
+
Return type:
+

np.ndarray

+
+
Raises:
+

ValueError – If the cell_index is greater than the number of cells.

+
+
+
+ +
+
+abstract get_sensor_data(exact_solution, num_points)[source]
+

Obtain sensor data (actual solution) at random points.

+

This method is used in the inverse problem to obtain the sensor data at random points within the domain. +Currently, it only works for problems with an analytical solution. +Methodologies to obtain sensor data for problems from a file are not implemented yet. +It is also not implemented for external or complex meshes.

+
+
Parameters:
+
    +
  • exact_solution (function) – A function that computes the exact solution at a given point.

  • +
  • num_points (int) – The number of random points to generate.

  • +
+
+
Returns:
+

A tuple containing the generated points and the exact solution at those points.

+
+
Return type:
+

tuple(numpy.ndarray, numpy.ndarray)

+
+
+
+ +
+
+abstract get_sensor_data_external(exact_sol, num_points, file_name)[source]
+

This method is used to obtain the sensor data from an external file.

+
+
Parameters:
+
    +
  • exact_sol (array-like) – The exact solution values.

  • +
  • num_points (int) – The number of points to sample from the data.

  • +
  • file_name (str) – The path to the file containing the sensor data.

  • +
+
+
Returns:
+

A tuple containing two arrays: +- points (ndarray): The sampled points from the data. +- exact_sol (ndarray): The corresponding exact solution values.

+
+
Return type:
+

tuple

+
+
+
+ +
+
+abstract get_shape_function_grad_x(cell_index) ndarray[source]
+

Get the gradient of the shape function with respect to the x-coordinate.

+
+
Parameters:
+

cell_index (int) – The index of the cell.

+
+
Returns:
+

An array containing the gradient of the shape function with respect to the x-coordinate.

+
+
Return type:
+

np.ndarray

+
+
Raises:
+

ValueError – If the cell_index is greater than the number of cells.

+
+
+

This function returns the actual values of the gradient of the shape function on a given cell.

+
+ +
+
+abstract get_shape_function_grad_x_ref(cell_index) ndarray[source]
+

Get the gradient of the shape function with respect to the x-coordinate on the reference element.

+
+
Parameters:
+

cell_index (int) – The index of the cell.

+
+
Returns:
+

An array containing the gradient of the shape function with respect to the x-coordinate.

+
+
Return type:
+

np.ndarray

+
+
Raises:
+

ValueError – If the cell_index is greater than the number of cells.

+
+
+
+ +
+
+abstract get_shape_function_grad_y(cell_index) ndarray[source]
+

Get the gradient of the shape function with respect to y at the given cell index.

+
+
Parameters:
+

cell_index (int) – The index of the cell.

+
+
Returns:
+

The gradient of the shape function with respect to y.

+
+
Return type:
+

np.ndarray

+
+
Raises:
+

ValueError – If the cell_index is greater than the total number of cells.

+
+
+
+ +
+
+abstract get_shape_function_grad_y_ref(cell_index)[source]
+

Get the gradient of the shape function with respect to y at the reference element.

+
+
Parameters:
+

cell_index (int) – The index of the cell.

+
+
Returns:
+

The gradient of the shape function with respect to y at the reference element.

+
+
Return type:
+

np.ndarray

+
+
Raises:
+

ValueError – If cell_index is greater than the number of cells.

+
+
+

This function returns the gradient of the shape function with respect to y at the reference element +for a given cell. The shape function gradient values are stored in the basis_grady_at_quad_ref array +of the corresponding finite element cell. The cell_index parameter specifies the index of the cell +for which the shape function gradient is required. If the cell_index is greater than the total number +of cells, a ValueError is raised.

+
+

Note

+

The returned gradient values are copied from the basis_grady_at_quad_ref array to ensure immutability.

+
+
+ +
+
+abstract get_shape_function_val(cell_index) ndarray[source]
+

Get the actual values of the shape functions on a given cell.

+
+
Parameters:
+

cell_index (int) – The index of the cell.

+
+
Returns:
+

An array containing the actual values of the shape functions.

+
+
Return type:
+

np.ndarray

+
+
Raises:
+

ValueError – If the cell_index is greater than the number of cells.

+
+
+
+ +
+
+abstract set_finite_elements() None[source]
+

Assigns the finite elements to each cell.

+

This method initializes the finite element objects for each cell in the mesh. +It creates an instance of the FE2D_Cell class for each cell, passing the necessary parameters. +The finite element objects store information about the basis functions, gradients, Jacobians, +quadrature points, weights, actual coordinates, and forcing functions associated with each cell.

+

After initializing the finite element objects, this method prints the shape details of various matrices +and updates the total number of degrees of freedom (dofs) for the entire mesh.

+
+
Returns:
+

None

+
+
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_rst/library/geometry/geometry.html b/_rst/library/geometry/geometry.html new file mode 100644 index 0000000..9764f27 --- /dev/null +++ b/_rst/library/geometry/geometry.html @@ -0,0 +1,202 @@ + + + + + + + fastvpinns.Geometry.geometry module — fastvpinns 1.0.0 documentation + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

fastvpinns.Geometry.geometry module

+

This module, geometry.py, contains the Geometry Abstract class which defines functions to read mesh from Gmsh and +generate internal mesh for 2D and 3D geometries.

+

Author: Thivin Anandh D +Date: 03-May-2024

+
+
+class fastvpinns.Geometry.geometry.Geometry(mesh_type, mesh_generation_method)[source]
+

Bases: object

+

Abstract class which defines functions to read mesh from Gmsh and internal mesh for 2D problems.

+
+
Parameters:
+
    +
  • mesh_type (str) – The type of mesh to be used.

  • +
  • mesh_generation_method (str) – The method used to generate the mesh.

  • +
+
+
+
+
+abstract generate_vtk_for_test()[source]
+

Generates a VTK from Mesh file (External) or using gmsh (for Internal).

+
+
Returns:
+

None

+
+
+
+ +
+
+abstract get_test_points()[source]
+

This function is used to extract the test points from the given mesh

+

Parameters: +None

+

Returns: +test_points (numpy.ndarray): The test points for the given domain

+
+ +
+
+abstract read_mesh(mesh_file: str, boundary_point_refinement_level: int, bd_sampling_method: str, refinement_level: int)[source]
+

Abstract method to read mesh from Gmsh.

+
+
Parameters:
+
    +
  • mesh_file (str) – The path to the mesh file.

  • +
  • boundary_point_refinement_level (int) – The refinement level of the boundary points.

  • +
  • bd_sampling_method (str) – The method used to sample the boundary points.

  • +
  • refinement_level (int) – The refinement level of the mesh.

  • +
+
+
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_rst/library/geometry/geometry2d.html b/_rst/library/geometry/geometry2d.html new file mode 100644 index 0000000..0420c5f --- /dev/null +++ b/_rst/library/geometry/geometry2d.html @@ -0,0 +1,273 @@ + + + + + + + fastvpinns.Geometry.geometry_2d module — fastvpinns 1.0.0 documentation + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

fastvpinns.Geometry.geometry_2d module

+

This module, geometry_2d.py, contains the Geometry_2D class which defines functions to read mesh from Gmsh and +generate internal mesh for 2D problems. It supports different types of meshes and mesh generation methods. +The class also allows for specifying the number of test points in the x and y directions, and the output folder for storing results.

+

Author: Thivin Anandh D +Date: 21-Sep-2023

+
+
+class fastvpinns.Geometry.geometry_2d.Geometry_2D(mesh_type: str, mesh_generation_method: str, n_test_points_x: int, n_test_points_y: int, output_folder: str)[source]
+

Bases: Geometry

+

Defines functions to read mesh from Gmsh and internal mesh for 2D problems.

+
+
Parameters:
+
    +
  • mesh_type (str) – The type of mesh to be used.

  • +
  • mesh_generation_method (str) – The method used to generate the mesh.

  • +
  • n_test_points_x (int) – The number of test points in the x-direction.

  • +
  • n_test_points_y (int) – The number of test points in the y-direction.

  • +
  • output_folder (str) – The path to the output folder.

  • +
+
+
+
+
+generate_quad_mesh_internal(x_limits: tuple, y_limits: tuple, n_cells_x: int, n_cells_y: int, num_boundary_points: int)[source]
+

Generate and save a quadrilateral mesh with physical curves.

+
+
Parameters:
+
    +
  • x_limits (tuple) – The lower and upper limits in the x-direction (x_min, x_max).

  • +
  • y_limits (tuple) – The lower and upper limits in the y-direction (y_min, y_max).

  • +
  • n_cells_x (int) – The number of cells in the x-direction.

  • +
  • n_cells_y (int) – The number of cells in the y-direction.

  • +
  • num_boundary_points (int) – The number of boundary points.

  • +
+
+
Returns:
+

The cell points and the dictionary of boundary points.

+
+
Return type:
+

tuple[numpy.ndarray, dict]

+
+
+
+ +
+
+generate_vtk_for_test()[source]
+

Generates a VTK from Mesh file (External) or using gmsh (for Internal).

+
+
Returns:
+

None

+
+
+
+ +
+
+get_test_points()[source]
+

This function is used to extract the test points from the given mesh

+

Parameters: +None

+

Returns: +test_points (numpy.ndarray): The test points for the given domain

+
+ +
+
+plot_adaptive_mesh(cells_list, area_averaged_cell_loss_list, epoch, filename='cell_residual')[source]
+

Plots the residuals in each cell of the mesh.

+
+
Parameters:
+
    +
  • cells_list (list) – The list of cells.

  • +
  • area_averaged_cell_loss_list (list) – The list of area averaged cell residual (or the normal residual).

  • +
  • epoch (int) – The epoch number (for file name).

  • +
  • filename (str, optional) – The name of the output file, defaults to “cell_residual”.

  • +
+
+
Returns:
+

None

+
+
+
+ +
+
+read_mesh(mesh_file: str, boundary_point_refinement_level: int, bd_sampling_method: str, refinement_level: int)[source]
+

Reads mesh from a Gmsh .msh file and extracts cell information.

+
+
Parameters:
+
    +
  • mesh_file (str) – The path to the mesh file.

  • +
  • boundary_point_refinement_level (int) – The number of boundary points to be generated.

  • +
  • bd_sampling_method (str) – The method used to generate the boundary points.

  • +
  • refinement_level (int) – The number of times the mesh should be refined.

  • +
+
+
Returns:
+

The cell points and the dictionary of boundary points.

+
+
Return type:
+

tuple

+
+
+
+ +
+
+write_vtk(solution, output_path, filename, data_names)[source]
+

Writes the data to a VTK file.

+
+
Parameters:
+
    +
  • solution (numpy.ndarray) – The solution vector.

  • +
  • output_path (str) – The path to the output folder.

  • +
  • filename (str) – The name of the output file.

  • +
  • data_names (list) – The list of data names in the VTK file to be written as scalars.

  • +
+
+
Returns:
+

None

+
+
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_rst/library/model/model.html b/_rst/library/model/model.html new file mode 100644 index 0000000..a022f71 --- /dev/null +++ b/_rst/library/model/model.html @@ -0,0 +1,232 @@ + + + + + + + fastvpinns.model.model module — fastvpinns 1.0.0 documentation + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

fastvpinns.model.model module

+

file: model.py +description: This file hosts the Neural Network (NN) model and the training loop for variational Physics-Informed Neural Networks (PINNs).

+
+

The focus is on the model architecture and the training loop, and not on the loss functions.

+
+

authors: Thivin Anandh D +changelog: 22/Sep/2023 - Initial implementation with basic model architecture and training loop +known_issues: None +dependencies: None specified.

+
+
+class fastvpinns.model.model.DenseModel(*args, **kwargs)[source]
+

Bases: Model

+

Defines the Dense Model for the Neural Network for solving Variational PINNs.

+
+
Parameters:
+
    +
  • layer_dims (list) – List of dimensions of the dense layers.

  • +
  • learning_rate_dict (dict) – The dictionary containing the learning rate parameters.

  • +
  • params_dict (dict) – The dictionary containing the parameters.

  • +
  • loss_function (function) – The loss function for the PDE.

  • +
  • input_tensors_list (list) – The list containing the input tensors.

  • +
  • orig_factor_matrices (list) – The list containing the original factor matrices.

  • +
  • force_function_list (tf.Tensor) – The force function matrix.

  • +
  • tensor_dtype (tf.DType) – The tensorflow dtype to be used for all the tensors.

  • +
  • use_attention (bool, optional) – Flag to use attention layer after input, defaults to False.

  • +
  • activation (str, optional) – The activation function to be used for the dense layers, defaults to “tanh”.

  • +
  • hessian (bool, optional) – Flag to use hessian loss, defaults to False.

  • +
+
+
+
+
+call(inputs)[source]
+

The call method for the model.

+
+
Parameters:
+

inputs (tf.Tensor) – The input tensor for the model.

+
+
Returns:
+

The output tensor of the model.

+
+
Return type:
+

tf.Tensor

+
+
+
+ +
+
+get_config()[source]
+

Get the configuration of the model.

+
+
Returns:
+

The configuration of the model.

+
+
Return type:
+

dict

+
+
+
+ +
+
+train_step(beta=10, bilinear_params_dict=None)[source]
+

The train step method for the model.

+
+
Parameters:
+
    +
  • beta (int, optional) – The beta parameter for the training step, defaults to 10.

  • +
  • bilinear_params_dict (dict, optional) – The dictionary containing the bilinear parameters, defaults to None.

  • +
+
+
Returns:
+

The output of the training step.

+
+
Return type:
+

varies based on implementation

+
+
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_rst/library/model/model_hard.html b/_rst/library/model/model_hard.html new file mode 100644 index 0000000..0630e17 --- /dev/null +++ b/_rst/library/model/model_hard.html @@ -0,0 +1,238 @@ + + + + + + + fastvpinns.model.model_hard module — fastvpinns 1.0.0 documentation + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

fastvpinns.model.model_hard module

+

file: model_hard.py +description: This file contains the DenseModel class which is a custom model for the Neural Network

+
+

for solving Variational PINNs. This model is used for enforcing hard boundary constraints +on the solution.

+
+

author: Thivin Anandh D, Divij Ghose, Sashikumaar Ganesan +date: 22/01/2024 +changelog: 22/01/2024 - file created

+
+

22/01/2024 -

+
+

known issues: None

+
+
+class fastvpinns.model.model_hard.DenseModel_Hard(*args, **kwargs)[source]
+

Bases: Model

+

The DenseModel_Hard class is a custom model class that hosts the neural network model.

+

The class inherits from the tf.keras.Model class and is used +to define the neural network model architecture and the training loop for FastVPINNs. +:param layer_dims: List of integers representing the number of neurons in each layer +:type layer_dims: list +:param learning_rate_dict: Dictionary containing the learning rate parameters +:type learning_rate_dict: dict +:param params_dict: Dictionary containing the parameters for the model +:type params_dict: dict +:param loss_function: Loss function for the model +:type loss_function: function +:param input_tensors_list: List of input tensors for the model +:type input_tensors_list: list +:param orig_factor_matrices: List of original factor matrices +:type orig_factor_matrices: list +:param force_function_list: List of force functions +:type force_function_list: list +:param tensor_dtype: Tensor data type +:type tensor_dtype: tf.DType +:param use_attention: Flag to use attention layer +:type use_attention: bool +:param activation: Activation function for the model +:type activation: str +:param hessian: Flag to compute hessian +:type hessian: bool

+
+
+call(inputs)[source]
+

This method is used to define the forward pass of the model.

+
+ +
+
+get_config()[source]
+

This method is used to get the configuration of the model.

+
+ +
+
+train_step(beta=10, bilinear_params_dict=None)[source]
+

This method is used to define the training step of the model.

+
+ +
+
+call(inputs)[source]
+

This method is used to define the forward pass of the model. +:param inputs: Input tensor +:type inputs: tf.Tensor +:return: Output tensor from the model +:rtype: tf.Tensor

+
+ +
+
+get_config()[source]
+

This method is used to get the configuration of the model. +:return: Configuration of the model +:rtype: dict

+
+ +
+
+train_step(beta=10, bilinear_params_dict=None)[source]
+

This method is used to define the training step of the mode. +:param bilinear_params_dict: Dictionary containing the bilinear parameters +:type bilinear_params_dict: dict +:return: Dictionary containing the loss values +:rtype: dict

+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_rst/library/model/model_inverse.html b/_rst/library/model/model_inverse.html new file mode 100644 index 0000000..0630b0c --- /dev/null +++ b/_rst/library/model/model_inverse.html @@ -0,0 +1,219 @@ + + + + + + + fastvpinns.model.model_inverse module — fastvpinns 1.0.0 documentation + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

fastvpinns.model.model_inverse module

+

file: model_inverse.py +description: This file hosts the Neural Network (NN) model and the training loop for variational Physics-Informed Neural Networks (PINNs).

+
+

This focuses on training variational PINNs for inverse problems where the inverse parameter is constant on the domain. +The focus is on the model architecture and the training loop, and not on the loss functions.

+
+

authors: Thivin Anandh D +changelog: 22/Sep/2023 - Initial implementation with basic model architecture and training loop +known_issues: Currently out of the box, supports only one constant inverse parameters. +dependencies: None specified.

+
+
+class fastvpinns.model.model_inverse.DenseModel_Inverse(*args, **kwargs)[source]
+

Bases: Model

+

A subclass of tf.keras.Model that defines a dense model for an inverse problem.

+
+
Parameters:
+
    +
  • layer_dims (list) – The dimensions of the layers in the model.

  • +
  • learning_rate_dict (dict) – A dictionary containing the learning rates.

  • +
  • params_dict (dict) – A dictionary containing the parameters of the model.

  • +
  • loss_function (function) – The loss function to be used in the model.

  • +
  • input_tensors_list (list) – A list of input tensors.

  • +
  • orig_factor_matrices (list) – The original factor matrices.

  • +
  • force_function_list (list) – A list of force functions.

  • +
  • sensor_list (list) – A list of sensors for the inverse problem.

  • +
  • inverse_params_dict (dict) – A dictionary containing the parameters for the inverse problem.

  • +
  • tensor_dtype (tf.DType) – The data type of the tensors.

  • +
  • use_attention (bool) – Whether to use attention mechanism in the model. Defaults to False.

  • +
  • activation (str) – The activation function to be used in the model. Defaults to ‘tanh’.

  • +
  • hessian (bool) – Whether to use Hessian in the model. Defaults to False.

  • +
+
+
+
+
+call(inputs)[source]
+

Applies the model to the input data.

+
+
Parameters:
+

inputs – The input data.

+
+
Returns:
+

The output of the model after applying all the layers.

+
+
+
+ +
+
+get_config()[source]
+

Returns the configuration of the model.

+

This method is used to serialize the model configuration. It returns a dictionary +containing all the necessary information to recreate the model.

+
+
Returns:
+

The configuration dictionary of the model.

+
+
Return type:
+

dict

+
+
+
+ +
+
+train_step(beta=10, bilinear_params_dict=None)[source]
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_rst/library/model/model_inverse_domain.html b/_rst/library/model/model_inverse_domain.html new file mode 100644 index 0000000..c534d83 --- /dev/null +++ b/_rst/library/model/model_inverse_domain.html @@ -0,0 +1,235 @@ + + + + + + + fastvpinns.model.model_inverse_domain module — fastvpinns 1.0.0 documentation + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

fastvpinns.model.model_inverse_domain module

+

file: model_inverse_domain.py +description: This file hosts the Neural Network (NN) model and the training loop for variational Physics-Informed Neural Networks (PINNs).

+
+

This focuses on training variational PINNs for inverse problems where the inverse parameter is constant over the entire domain. +The focus is on the model architecture and the training loop, and not on the loss functions.

+
+

authors: Thivin Anandh D +changelog: 22/Sep/2023 - Initial implementation with basic model architecture and training loop +known_issues: None +dependencies: None specified.

+
+
+class fastvpinns.model.model_inverse_domain.DenseModel_Inverse_Domain(*args, **kwargs)[source]
+

Bases: Model

+

A subclass of tf.keras.Model that defines a dense model for an inverse problem.

+
+
Parameters:
+
    +
  • layer_dims (list) – The dimensions of the layers in the model.

  • +
  • learning_rate_dict (dict) – A dictionary containing the learning rates.

  • +
  • params_dict (dict) – A dictionary containing the parameters of the model.

  • +
  • loss_function (function) – The loss function to be used in the model.

  • +
  • input_tensors_list (list) – A list of input tensors.

  • +
  • orig_factor_matrices (list) – The original factor matrices.

  • +
  • force_function_list (list) – A list of force functions.

  • +
  • sensor_list (list) – A list of sensors for the inverse problem.

  • +
  • inverse_params_dict (dict) – A dictionary containing the parameters for the inverse problem.

  • +
  • tensor_dtype (tf.DType) – The data type of the tensors.

  • +
  • use_attention (bool) – Whether to use attention mechanism in the model. Defaults to False.

  • +
  • activation (str) – The activation function to be used in the model. Defaults to ‘tanh’.

  • +
  • hessian (bool) – Whether to use Hessian in the model. Defaults to False.

  • +
+
+
+
+
+call(inputs)[source]
+

The call method for the model.

+
+
Parameters:
+

inputs (tf.Tensor) – The input tensor for the model.

+
+
Returns:
+

The output tensor of the model.

+
+
Return type:
+

tf.Tensor

+
+
+
+ +
+
+get_config()[source]
+

Get the configuration of the model.

+
+
Returns:
+

The configuration of the model.

+
+
Return type:
+

dict

+
+
+
+ +
+
+train_step(beta=10, bilinear_params_dict=None)[source]
+

The train step method for the model.

+
+
Parameters:
+
    +
  • beta (int, optional) – The beta parameter for the training step, defaults to 10.

  • +
  • bilinear_params_dict (dict, optional) – The dictionary containing the bilinear parameters, defaults to None.

  • +
+
+
Returns:
+

The output of the training step.

+
+
Return type:
+

varies based on implementation

+
+
+
+ +
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_rst/library/physics/cd2d.html b/_rst/library/physics/cd2d.html new file mode 100644 index 0000000..f3a5786 --- /dev/null +++ b/_rst/library/physics/cd2d.html @@ -0,0 +1,180 @@ + + + + + + + fastvpinns.physics.cd2d module — fastvpinns 1.0.0 documentation + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

fastvpinns.physics.cd2d module

+

This function is implemntation of our efficient tensor-based loss calculation for cd2d equation +Author: Thivin Anandh D +Date: 21-Sep-2023 +History: Initial implementation +Refer: https://arxiv.org/abs/2404.12063

+
+
+fastvpinns.physics.cd2d.pde_loss_cd2d(test_shape_val_mat, test_grad_x_mat, test_grad_y_mat, pred_nn, pred_grad_x_nn, pred_grad_y_nn, forcing_function, bilinear_params)[source]
+

Calculates and returns the loss for the CD2D problem

+
+
Parameters:
+
    +
  • test_shape_val_mat (tf.Tensor) – The test shape value matrix.

  • +
  • test_grad_x_mat (tf.Tensor) – The x-gradient of the test matrix.

  • +
  • test_grad_y_mat (tf.Tensor) – The y-gradient of the test matrix.

  • +
  • pred_nn (tf.Tensor) – The predicted neural network output.

  • +
  • pred_grad_x_nn (tf.Tensor) – The x-gradient of the predicted neural network output.

  • +
  • pred_grad_y_nn (tf.Tensor) – The y-gradient of the predicted neural network output.

  • +
  • forcing_function (function) – The forcing function used in the PDE.

  • +
  • bilinear_params (list) – The parameters for the bilinear form.

  • +
+
+
Returns:
+

The calculated loss.

+
+
Return type:
+

tf.Tensor

+
+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_rst/library/physics/cd2d_inverse.html b/_rst/library/physics/cd2d_inverse.html new file mode 100644 index 0000000..d5f9982 --- /dev/null +++ b/_rst/library/physics/cd2d_inverse.html @@ -0,0 +1,180 @@ + + + + + + + fastvpinns.physics.cd2d_inverse module — fastvpinns 1.0.0 documentation + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

fastvpinns.physics.cd2d_inverse module

+

This function is implemntation of our efficient tensor-based loss calculation for cd2d equation with inverse problem (Constant) +Author: Thivin Anandh D +Date: 21-Sep-2023 +History: Initial implementation +Refer: https://arxiv.org/abs/2404.12063

+
+
+fastvpinns.physics.cd2d_inverse.pde_loss_cd2d(test_shape_val_mat, test_grad_x_mat, test_grad_y_mat, pred_nn, pred_grad_x_nn, pred_grad_y_nn, forcing_function, bilinear_params_dict, inverse_param_dict)[source]
+

Calculates and returns the loss for the CD2D problem Inverse (constant)

+
+
Parameters:
+
    +
  • test_shape_val_mat (tf.Tensor) – The test shape value matrix.

  • +
  • test_grad_x_mat (tf.Tensor) – The x-gradient of the test matrix.

  • +
  • test_grad_y_mat (tf.Tensor) – The y-gradient of the test matrix.

  • +
  • pred_nn (tf.Tensor) – The predicted neural network output.

  • +
  • pred_grad_x_nn (tf.Tensor) – The x-gradient of the predicted neural network output.

  • +
  • pred_grad_y_nn (tf.Tensor) – The y-gradient of the predicted neural network output.

  • +
  • forcing_function (function) – The forcing function used in the PDE.

  • +
  • bilinear_params_dict (dict) – The dictionary containing the bilinear parameters.

  • +
  • inverse_param_dict (dict) – The dictionary containing the parameters for the inverse problem.

  • +
+
+
Returns:
+

The calculated loss.

+
+
Return type:
+

tf.Tensor

+
+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_rst/library/physics/cd2d_inverse_domain.html b/_rst/library/physics/cd2d_inverse_domain.html new file mode 100644 index 0000000..530276b --- /dev/null +++ b/_rst/library/physics/cd2d_inverse_domain.html @@ -0,0 +1,179 @@ + + + + + + + fastvpinns.physics.cd2d_inverse_domain module — fastvpinns 1.0.0 documentation + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

fastvpinns.physics.cd2d_inverse_domain module

+

This function is implemntation of our efficient tensor-based loss calculation for cd2d equation with inverse problem (Domain) +Author: Thivin Anandh D +Date: 21-Sep-2023 +History: Initial implementation +Refer: https://arxiv.org/abs/2404.12063

+
+
+fastvpinns.physics.cd2d_inverse_domain.pde_loss_cd2d_inverse_domain(test_shape_val_mat, test_grad_x_mat, test_grad_y_mat, pred_nn, pred_grad_x_nn, pred_grad_y_nn, forcing_function, bilinear_params, inverse_params_list)[source]
+

Calculates and returns the loss for the CD2D inverse problem (Domain)

+
+
Parameters:
+
    +
  • test_shape_val_mat (tf.Tensor) – The test shape value matrix.

  • +
  • test_grad_x_mat (tf.Tensor) – The x-gradient of the test matrix.

  • +
  • test_grad_y_mat (tf.Tensor) – The y-gradient of the test matrix.

  • +
  • pred_nn (tf.Tensor) – The predicted neural network output.

  • +
  • pred_grad_x_nn (tf.Tensor) – The x-gradient of the predicted neural network output.

  • +
  • pred_grad_y_nn (tf.Tensor) – The y-gradient of the predicted neural network output.

  • +
  • forcing_function (function) – The forcing function used in the PDE.

  • +
  • bilinear_params (list) – The parameters for the bilinear form.

  • +
  • inverse_params_list (list) – The parameters for the inverse problem.

  • +
+
+
Returns:
+

The calculated loss.

+
+
Return type:
+

tf.Tensor

+
+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_rst/library/physics/helmholtz2d.html b/_rst/library/physics/helmholtz2d.html new file mode 100644 index 0000000..d1c4c34 --- /dev/null +++ b/_rst/library/physics/helmholtz2d.html @@ -0,0 +1,180 @@ + + + + + + + fastvpinns.physics.helmholtz2d module — fastvpinns 1.0.0 documentation + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

fastvpinns.physics.helmholtz2d module

+

This function is implemntation of our efficient tensor-based loss calculation for Helmholtz equation with inverse problem (Domain) +Author: Thivin Anandh D +Date: 21-Sep-2023 +History: Initial implementation +Refer: https://arxiv.org/abs/2404.12063

+
+
+fastvpinns.physics.helmholtz2d.pde_loss_helmholtz(test_shape_val_mat, test_grad_x_mat, test_grad_y_mat, pred_nn, pred_grad_x_nn, pred_grad_y_nn, forcing_function, bilinear_params)[source]
+

Calculates and returns the loss for the helmholtz problem

+
+
Parameters:
+
    +
  • test_shape_val_mat (tf.Tensor) – The test shape value matrix.

  • +
  • test_grad_x_mat (tf.Tensor) – The x-gradient of the test matrix.

  • +
  • test_grad_y_mat (tf.Tensor) – The y-gradient of the test matrix.

  • +
  • pred_nn (tf.Tensor) – The predicted neural network output.

  • +
  • pred_grad_x_nn (tf.Tensor) – The x-gradient of the predicted neural network output.

  • +
  • pred_grad_y_nn (tf.Tensor) – The y-gradient of the predicted neural network output.

  • +
  • forcing_function (function) – The forcing function used in the PDE.

  • +
  • bilinear_params (list) – The parameters for the bilinear form.

  • +
+
+
Returns:
+

The calculated loss.

+
+
Return type:
+

tf.Tensor

+
+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_rst/library/physics/poisson2d.html b/_rst/library/physics/poisson2d.html new file mode 100644 index 0000000..d33d534 --- /dev/null +++ b/_rst/library/physics/poisson2d.html @@ -0,0 +1,160 @@ + + + + + + + fastvpinns.physics.poisson2d module — fastvpinns 1.0.0 documentation + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

fastvpinns.physics.poisson2d module

+

This function is implemntation of our efficient tensor-based loss calculation for poisson equation +Author: Thivin Anandh D +Date: 21-Sep-2023 +History: Initial implementation +Refer: https://arxiv.org/abs/2404.12063

+
+
+fastvpinns.physics.poisson2d.pde_loss_poisson(test_shape_val_mat, test_grad_x_mat, test_grad_y_mat, pred_nn, pred_grad_x_nn, pred_grad_y_nn, forcing_function, bilinear_params)[source]
+

This method returns the loss for the Poisson Problem of the PDE

+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_rst/library/physics/poisson2d_inverse.html b/_rst/library/physics/poisson2d_inverse.html new file mode 100644 index 0000000..3386bb1 --- /dev/null +++ b/_rst/library/physics/poisson2d_inverse.html @@ -0,0 +1,180 @@ + + + + + + + fastvpinns.physics.poisson2d_inverse module — fastvpinns 1.0.0 documentation + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

fastvpinns.physics.poisson2d_inverse module

+

This function is implemntation of our efficient tensor-based loss calculation for poisson equation with inverse problem (constant) +Author: Thivin Anandh D +Date: 21-Sep-2023 +History: Initial implementation +Refer: https://arxiv.org/abs/2404.12063

+
+
+fastvpinns.physics.poisson2d_inverse.pde_loss_poisson_inverse(test_shape_val_mat, test_grad_x_mat, test_grad_y_mat, pred_nn, pred_grad_x_nn, pred_grad_y_nn, forcing_function, bilinear_params, inverse_params_dict)[source]
+

Calculates and returns the loss for the Poisson problem Inverse (constant)

+
+
Parameters:
+
    +
  • test_shape_val_mat (tf.Tensor) – The test shape value matrix.

  • +
  • test_grad_x_mat (tf.Tensor) – The x-gradient of the test matrix.

  • +
  • test_grad_y_mat (tf.Tensor) – The y-gradient of the test matrix.

  • +
  • pred_nn (tf.Tensor) – The predicted neural network output.

  • +
  • pred_grad_x_nn (tf.Tensor) – The x-gradient of the predicted neural network output.

  • +
  • pred_grad_y_nn (tf.Tensor) – The y-gradient of the predicted neural network output.

  • +
  • forcing_function (function) – The forcing function used in the PDE.

  • +
  • bilinear_params_dict (dict) – The dictionary containing the bilinear parameters.

  • +
  • inverse_param_dict (dict) – The dictionary containing the parameters for the inverse problem.

  • +
+
+
Returns:
+

The calculated loss.

+
+
Return type:
+

tf.Tensor

+
+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_rst/library/utils/compute_utils.html b/_rst/library/utils/compute_utils.html new file mode 100644 index 0000000..4abed94 --- /dev/null +++ b/_rst/library/utils/compute_utils.html @@ -0,0 +1,336 @@ + + + + + + + fastvpinns.utils.compute_utils module — fastvpinns 1.0.0 documentation + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

fastvpinns.utils.compute_utils module

+

filename: compute_utils.py +description: This file contains the utility functions for

+
+

computing the errors between the exact and +predicted solutions

+
+

author: Thivin Anandh D +date: 02/11/2023 +changelog: 02/11/2023 - file created

+
+

02/11/2023 - added functions to compute L1, L2, L_inf errors

+
+

known_issues: None

+
+
+fastvpinns.utils.compute_utils.compute_errors_combined(u_exact, u_approx)[source]
+

This function will compute the L1, L2 and L_inf absolute and relative errors. +:param u_exact: numpy array containing the exact solution +:type u_exact: numpy.ndarray +:param u_approx: numpy array containing the approximate solution +:type u_approx: numpy.ndarray +:return: L1, L2 and L_inf absolute and relative errors +:rtype: tuple

+
+ +
+
+fastvpinns.utils.compute_utils.compute_l1_error(u_exact, u_approx)[source]
+

This function will compute the L1 error between the exact solution and the approximate solution. +The L1 error is defined as: +..math:

+
\frac{1}{N} \sum_{i=1}^{N} |u_{exact} - u_{approx}|
+
+
+
+
Parameters:
+
    +
  • u_exact (numpy.ndarray) – numpy array containing the exact solution

  • +
  • u_approx (numpy.ndarray) – numpy array containing the approximate solution

  • +
+
+
Returns:
+

L1 error between the exact and approximate solutions

+
+
Return type:
+

float

+
+
+
+ +
+
+fastvpinns.utils.compute_utils.compute_l1_error_relative(u_exact, u_approx)[source]
+

This function will compute the relative L1 error between the exact solution and the approximate solution. +The relative L1 error is defined as:

+
+
+
..math::

frac{frac{1}{N} sum_{i=1}^{N} |u_{exact} - u_{approx}|}{frac{1}{N} sum_{i=1}^{N} |u_{exact}|}

+
+
+
+
+
Parameters:
+
    +
  • u_exact (numpy.ndarray) – numpy array containing the exact solution

  • +
  • u_approx (numpy.ndarray) – numpy array containing the approximate solution

  • +
+
+
Returns:
+

relative L1 error between the exact and approximate solutions

+
+
Return type:
+

float

+
+
+
+ +
+
+fastvpinns.utils.compute_utils.compute_l2_error(u_exact, u_approx)[source]
+

This function will compute the L2 error between the exact solution and the approximate solution. +The L2 error is defined as:

+
+
..math::

sqrt{frac{1}{N} sum_{i=1}^{N} (u_{exact} - u_{approx})^2}

+
+
+
+
Parameters:
+
    +
  • u_exact (numpy.ndarray) – numpy array containing the exact solution

  • +
  • u_approx (numpy.ndarray) – numpy array containing the approximate solution

  • +
+
+
Returns:
+

L2 error between the exact and approximate solutions

+
+
Return type:
+

float

+
+
+
+ +
+
+fastvpinns.utils.compute_utils.compute_l2_error_relative(u_exact, u_approx)[source]
+

This function will compute the relative L2 error between the exact solution and the approximate solution. +The relative L2 error is defined as:

+
+
+
..math::

frac{sqrt{frac{1}{N} sum_{i=1}^{N} (u_{exact} - u_{approx})^2}}{sqrt{frac{1}{N} sum_{i=1}^{N} u_{exact}^2}}

+
+
+
+
+
Parameters:
+
    +
  • u_exact (numpy.ndarray) – numpy array containing the exact solution

  • +
  • u_approx (numpy.ndarray) – numpy array containing the approximate solution

  • +
+
+
Returns:
+

relative L2 error between the exact and approximate solutions

+
+
Return type:
+

float

+
+
+
+ +
+
+fastvpinns.utils.compute_utils.compute_linf_error(u_exact, u_approx)[source]
+

This function will compute the L_inf error between the exact solution and the approximate solution. +The L_inf error is defined as

+
+
+
..math::

max_{i=1}^{N} |u_{exact} - u_{approx}|

+
+
+
+
+
Parameters:
+
    +
  • u_exact (numpy.ndarray) – numpy array containing the exact solution

  • +
  • u_approx (numpy.ndarray) – numpy array containing the approximate solution

  • +
+
+
Returns:
+

L_inf error between the exact and approximate solutions

+
+
Return type:
+

float

+
+
+
+ +
+
+fastvpinns.utils.compute_utils.compute_linf_error_relative(u_exact, u_approx)[source]
+

This function will compute the relative L_inf error between the exact solution and the approximate solution. +The relative L_inf error is defined as:

+
+
+
..math::

frac{max_{i=1}^{N} |u_{exact} - u_{approx}|}{max_{i=1}^{N} |u_{exact}|}

+
+
+
+
+
Parameters:
+
    +
  • u_exact (numpy.ndarray) – numpy array containing the exact solution

  • +
  • u_approx (numpy.ndarray) – numpy array containing the approximate solution

  • +
+
+
Returns:
+

relative L_inf error between the exact and approximate solutions

+
+
Return type:
+

float

+
+
+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_rst/library/utils/plot_utils.html b/_rst/library/utils/plot_utils.html new file mode 100644 index 0000000..2d33d5e --- /dev/null +++ b/_rst/library/utils/plot_utils.html @@ -0,0 +1,301 @@ + + + + + + + fastvpinns.utils.plot_utils module — fastvpinns 1.0.0 documentation + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

fastvpinns.utils.plot_utils module

+

filename: plot_utils.py +description: This file contains the utility functions for

+
+

plotting the loss functions and the predicted inverse parameters

+
+

author: Thivin Anandh D +date: 02/11/2023 +changelog: 02/11/2023 - file created

+
+
+
02/11/2023 - added functions to plot the loss functions and the predicted

inverse parameters

+
+
+
+

known_issues: None

+
+
+fastvpinns.utils.plot_utils.plot_array(array, output_path, filename, title, x_label='Epochs', y_label='Loss')[source]
+

This function will plot the loss function. +:param array: list of loss values +:type array: list +:param output_path: path to save the plot +:type output_path: str +:param filename: filename to save the plot +:type filename: str +:param title: title of the plot +:type title: str +:param x_label: x-axis label, defaults to “Epochs” +:type x_label: str, optional +:param y_label: y-axis label, defaults to “Loss” +:type y_label: str, optional +:return: None +:rtype: None

+
+ +
+
+fastvpinns.utils.plot_utils.plot_contour(x, y, z, output_path, filename, title)[source]
+

This function will plot the contour plot. +:param x: x values +:type x: numpy.ndarray +:param y: y values +:type y: numpy.ndarray +:param z: z values +:type z: numpy.ndarray +:param output_path: path to save the plot +:type output_path: str +:param filename: filename to save the plot +:type filename: str +:param title: title of the plot +:type title: str +:return: None +:rtype: None

+
+ +
+
+fastvpinns.utils.plot_utils.plot_inverse_param_function(inverse_predicted, inverse_param_name, actual_value, output_path, file_prefix)[source]
+

This function will plot the predicted inverse parameter. +:param inverse_predicted: list of predicted inverse parameter values +:type inverse_predicted: list +:param inverse_param_name: name of the inverse parameter +:type inverse_param_name: str +:param actual_value: actual value of the inverse parameter +:type actual_value: float +:param output_path: path to save the plot +:type output_path: str +:param file_prefix: prefix for the filename +:type file_prefix: str +:return: None +:rtype: None

+
+ +
+
+fastvpinns.utils.plot_utils.plot_inverse_test_loss_function(loss_function, output_path)[source]
+

This function will plot the test loss function of the inverse parameter. +:param loss_function: list of loss values +:type loss_function: list +:param output_path: path to save the plot +:type output_path: str +:return: None +:rtype: None

+
+ +
+
+fastvpinns.utils.plot_utils.plot_loss_function(loss_function, output_path)[source]
+

This function will plot the loss function. +:param loss_function: list of loss values +:type loss_function: list +:param output_path: path to save the plot +:type output_path: str +:return: None +:rtype: None

+
+ +
+
+fastvpinns.utils.plot_utils.plot_multiple_loss_function(loss_function_list, output_path, filename, legend_labels, y_label, title, x_label='Epochs')[source]
+

This function will plot the loss function in log scale for multiple parameters. +:param loss_function_list: list of loss values for multiple parameters +:type loss_function_list: list +:param output_path: path to save the plot +:type output_path: str +:param filename: filename to save the plot +:type filename: str +:param legend_labels: list of legend labels +:type legend_labels: list +:param y_label: y-axis label +:type y_label: str +:param title: title of the plot +:type title: str +:param x_label: x-axis label, defaults to “Epochs” +:type x_label: str, optional +:return: None +:rtype: None

+
+ +
+
+fastvpinns.utils.plot_utils.plot_test_loss_function(loss_function, output_path, fileprefix='')[source]
+

This function will plot the test loss function. +:param loss_function: list of loss values +:type loss_function: list +:param output_path: path to save the plot +:type output_path: str +:param fileprefix: prefix for the filename, defaults to “” +:type fileprefix: str, optional +:return: None +:rtype: None

+
+ +
+
+fastvpinns.utils.plot_utils.plot_test_time_loss_function(time_array, loss_function, output_path)[source]
+

This function will plot the test loss as a function of time in seconds. +:param time_array: array of time values +:type time_array: numpy.ndarray +:param loss_function: list of loss values +:type loss_function: list +:param output_path: path to save the plot +:type output_path: str +:return: None +:rtype: None

+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_rst/library/utils/print_utils.html b/_rst/library/utils/print_utils.html new file mode 100644 index 0000000..d64199c --- /dev/null +++ b/_rst/library/utils/print_utils.html @@ -0,0 +1,163 @@ + + + + + + + fastvpinns.utils.print_utils module — fastvpinns 1.0.0 documentation + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

fastvpinns.utils.print_utils module

+
+
+fastvpinns.utils.print_utils.print_table(title, columns, col_1_values, col_2_values)[source]
+

This function prints a table with two columns to the console. +:param title: Title of the table +:type title: str +:param columns: List of column names +:type columns: list +:param col_1_values: List of values for column 1 +:type col_1_values: list +:param col_2_values: List of values for column 2 +:type col_2_values: list +:return: None +:rtype: None

+
+ +
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_rst/modules.html b/_rst/modules.html new file mode 100644 index 0000000..f5aacb9 --- /dev/null +++ b/_rst/modules.html @@ -0,0 +1,235 @@ + + + + + + + fastvpinns — fastvpinns 1.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

fastvpinns

+
+ +
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_rst/tutorials/forward_problems_2d/complex_mesh/cd2d/cd2d.html b/_rst/tutorials/forward_problems_2d/complex_mesh/cd2d/cd2d.html new file mode 100644 index 0000000..c410bb0 --- /dev/null +++ b/_rst/tutorials/forward_problems_2d/complex_mesh/cd2d/cd2d.html @@ -0,0 +1,892 @@ + + + + + + + Convection Diffusion 2D Example on Circular Domain — fastvpinns 1.0.0 documentation + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Convection Diffusion 2D Example on Circular Domain

+

This example demonstrates how to solve a Poisson equation in 2D on a circular domain using the fastvpinns package. +All the necessary files can be found in the examples folder of the fastvpinns GitHub repository

+

The Poisson equation is given by

+
+\[-\epsilon \nabla^2 u + \mathbf{b} \cdot \nabla u + cu = f \quad \text{in} \quad \Omega\]
+

where \(\Omega\) is the circular domain and \(f\) is the source term. The boundary conditions are given by

+
+\[u = \cos(x^2 + y^2) \quad \text{on} \quad \partial \Omega\]
+

For this problem, the parameters are

+
+\[ \begin{align}\begin{aligned}f = 4x^2\cos(x^2 + y^2) - 2x\sin(x^2 + y^2) + 4y^2\cos(x^2 + y^2) + 4\sin(x^2 + y^2)\\\epsilon = 1, \mathbf{b} = [1, 0], c = 0\end{aligned}\end{align} \]
+

The exact solution is given by

+
+\[u = cos(x^2 +y^2)\]
+

Note : The forcing formulation for this problem is obtained by +substituting the exact solution into the cd2d equation with given pde +parameters.

+
+

Computational Domain

+

The computational domain is a circular domain with radius 1 centered at +(0, 0).

+
+alt text +
+
+

Contents

+ +
+
+

Steps to run the code

+

To run the code, execute the following command:

+
python3 main_cd2d.py input.yaml
+
+
+
+
+

Example File - cd2d_example.py

+

This file hosts all the details about the bilinear parameters for the +PDE, boundary conditions, source term, and the exact solution.

+
+

Defining the boundary conditions

+

The function circle_boundary returns the boundary value for a given +component of the boundary. The function get_boundary_function_dict +returns a dictionary of boundary functions. The key of the dictionary is +the boundary id and the value is the boundary function. The function +get_bound_cond_dict returns a dictionary of boundary conditions. The +key of the dictionary is the boundary id and the value is the boundary +condition.

+
+Unit Circle +
+

For externally created geometries from gmsh, the user needs to provide +the physical tag for the boundaries present in the geometry. +In our case, we have used 1000 to define the circular boundary in mesh file.

+

Note : As of now, only Dirichlet boundary conditions are supported.

+
def circle_boundary(x, y):
+    """
+    This function will return the boundary value for given component of a boundary
+    """
+    return 0.0
+
+def get_boundary_function_dict():
+    """
+    This function will return a dictionary of boundary functions
+    """
+    return {1000: circle_boundary}
+
+
+def get_bound_cond_dict():
+    """
+    This function will return a dictionary of boundary conditions
+    """
+    return {1000: "dirichlet"}
+
+
+
+
+

Defining the source term

+

The function rhs returns the value of the source term at a given +point.

+
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
+
+
+

Return to top

+
+
+

Defining the exact solution

+

The function exact_solution returns the value of the exact solution +at a given point.

+
def exact_solution(x, y):
+    """
+    This function will return the value of the exact solution at a given point
+    """
+    u_temp = 16 * x * (1 - x) * y * (1 - y)
+
+    return u_temp
+
+
+

Return to top

+
+
+

Defining the bilinear form

+

The function get_bilinear_params_dict returns a dictionary of +bilinear parameters. The dictionary contains the values of the +parameters \(\epsilon\) (epsilon), \(b_x\) (convection in +x-direction), \(b_y\) (convection in y-direction), and \(c\) +(reaction term).

+

Note : If any of the bilinear parameters are not present in the +dictionary (for the cd2d model), then the code will throw an error.

+
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}
+
+
+

Return to top

+
+
+
+

Input File

+

This is the file that contains all the details about the problem. The +input file is in the YAML format. The input file for this example is +given below. The contents of the yaml files are as follows

+
+
+
+

Experimentation

+

Defines the output path where the results will be saved.

+
experimentation:
+  output_path: "output/cd2d/1"  # Path to the output directory where the results will be saved.
+
+
+

Return to top

+
+
+

Geometry

+

It contains the details about the geometry of the domain. The mesh +generation method can be either “internal” or “external”. If the mesh +generation method is “internal”, then the internal_mesh_params are +used to generate the mesh. If the mesh generation method is “external”, +then the mesh is read from the file specified in the mesh_file +parameter.

+
    +
  • In this case, we will use an external mesh. The mesh +../meshes/circle_quad.mesh is generated using the Gmsh software. +The mesh needs to have physical elements defined for the boundary. In +this case, the physical element is defined as 1000 (which is defined +in the circle_boundary function in the cd2d_example.py file).

  • +
  • exact_solution_generation is set to “internal” which means that +the exact solution is generated using the exact_solution function +in the cd2d_example.py file. For external check the other +examples cd2d_gear

  • +
  • mesh_type is set to “quadrilateral” which means that the mesh is +a quadrilateral mesh. Note: As of now, only quadrilateral meshes are +supported.

  • +
  • boundary_refinement_level is set to 4 which means that the +boundary is refined 4 times. (i.e), when the mesh is read, only the +boundary points of an edge in quadrilateral mesh are read. this +refinement will refine the boundary points to get more boundary +points within the edge.

  • +
  • boundary_sampling_method is set to “uniform” which means that the +boundary points are sampled using the “uniform” method. (Use only +uniform sampling as of now.)

  • +
  • generate_mesh_plot is set to True which means that the mesh plot +is generated and saved in the output directory.

  • +
+
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: "internal" # 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".
+
+
+

Return to top

+
+
+

Finite Element Space

+

This section contains the details about the finite element spaces.

+
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"
+
+
+

Here the fe_order is set to 6 which means it has 6 basis functions +in each direction. The quad_order is set to 10 which means it uses a +10-points in each direction for the quadrature rule. The supported +quadrature rules are “gauss-jacobi” and “gauss-legendre”. In this +version of code, both “jacobi” and “legendre” refer to the same basis +functions (to maintain backward compatibility). The basis functions are +special type of Jacobi polynomials defined by

+
+\[J_{n} = J_{n-1} - J_{n+1}\]
+

, where J n is the nth Jacobi polynomial.

+

Return to top

+
+
+

pde

+

This value provides the beta values for the Dirichlet boundary conditions. The beta values are the multipliers that are used to multiply the boundary losses.

+
+\[loss_{total} = loss_{pde} + \beta \cdot loss_{dirichlet}\]
+
pde:
+  beta: 10  # Parameter for the PDE.
+
+
+

Return to top

+
+
+

model

+

The model section contains the details about the dense model to be used. +The model architecture is given by the model_architecture parameter. +The activation function used in the model is given by the activation +parameter. The epochs parameter is the number of training epochs. +The dtype parameter is the data type used for computations. The +learning_rate section contains the parameters for learning rate +scheduling. The initial_learning_rate parameter is the initial +learning rate. The use_lr_scheduler parameter is a flag indicating +whether to use the learning rate scheduler. The decay_steps +parameter is the number of steps between each learning rate decay. The +decay_rate parameter is the decay rate for the learning rate. The +staircase parameter is a flag indicating whether to use the +staircase decay.

+

Any parameter which are not mentioned above are archived parameters, +which are not used in the current version of the code. (like +use_attention, set_memory_growth)

+
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
+
+
+

Return to top

+
+
+

logging

+

update_console_output defines the epochs at which you need to log +parameters like loss, time taken, etc.

+
logging:
+  update_console_output: 100  # Number of epochs after which to update the console output.
+
+
+

The other parameters such as update_progress_bar, +update_solution_images are archived parameters which are not used in +the current version of the code.

+

Return to top

+
+

Main File - main_cd2d.py

+

This file contains the main code to solve the Poisson equation in 2D on +a circular domain. The code reads the input file, sets up the problem, +and solves the Poisson equation using the fastvpinns package.

+
+
+
+

Importing the required libraries

+

The following libraries are imported in the main file.

+
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
+
+
+

Return to top

+
+
+

imports from fastvpinns

+

The following imports are used from the fastvpinns package.

+
    +
  • Imports the geometry module from the fastvpinns package, which +contains the Geometry_2D class responsible for setting up the +geometry of the domain.

  • +
+
from fastvpinns.Geometry.geometry_2d import Geometry_2D
+
+
+
    +
  • Imports the fespace module from the fastvpinns package, which +contains the FE class responsible for setting up the finite +element spaces.

  • +
+
from fastvpinns.FE.fespace2d import Fespace2D
+
+
+
    +
  • Imports the datahandler module from the fastvpinns package, which +contains the DataHandler class responsible for handling and +converting the data to necessary shape for training purposes

  • +
+
from fastvpinns.DataHandler.datahandler import DataHandler
+
+
+
    +
  • Imports the model module from the fastvpinns package, which +contains the Model class responsible for training the neural +network model.

  • +
+
from fastvpinns.Model.model import DenseModel
+
+
+
    +
  • Import the Loss module from the fastvpinns package, which +contains the loss function of the PDE to be solved in tensor form.

  • +
+
from fastvpinns.physics.cd2d import pde_loss_cd2d
+
+
+
    +
  • Import additional functionalities from the fastvpinns package.

  • +
+
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
+
+
+

Return to top

+
+
+

Reading the input file

+

The input file is read using the yaml library.

+
if len(sys.argv) != 2:
+        print("Usage: python main.py <input file>")
+        sys.exit(1)
+
+    # Read the YAML file
+    with open(sys.argv[1], 'r') as f:
+        config = yaml.safe_load(f)
+
+
+
+
+

Reading all input parameters

+
# 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_console_output = config['logging']['update_console_output']
+
+
+

all the variables which are named with the prefix i_ are input +parameters which are read from the input file. Return to +top

+
+
+

Set up the geometry

+

Obtain the bounndary condition and boundary values from the +cd2d_example.py file and initialise the Geometry_2D class. After +that use the domain.read_mesh functionality to read the external +mesh file.

+
cells, boundary_points = domain.read_mesh(
+        i_mesh_file_name,
+        i_boundary_refinement_level,
+        i_boundary_sampling_method,
+        refinement_level=1,
+    )
+
+
+

Return to top

+
+
+

Setup fespace

+

Initialise the Fespace2D class with the required parameters.

+
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,
+    )
+
+
+

Return to top

+
+
+

Setup datahandler

+

Initialise the DataHandler class with the required parameters.

+
datahandler = DataHandler2D(fespace, domain, dtype=i_dtype)
+
+
+

Return to top

+
+
+

Setup model

+

Setup the necessary parameters for the model and initialise the Model +class. Before that fill the params dictionary with the required +parameters.

+
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,
+    )
+
+
+

Return to top

+
+
+

Pre-train setup

+
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)
+
+
+

This sets up the test points and the exact solution. The progress bar is +initialised and the loss arrays are set up. The beta value is set up as +a constant tensor. Return to top

+
+
+

Training

+
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'])
+
+
+

This train_step function trains the model for one epoch and returns +the loss. The loss is appended to the loss array. Then for every epoch +where +(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}"
+)
+
+
+

We will compute all the test errors and write the solution to a vtk file +for a complex mesh. Further, the console output will be printed with the +loss values and the test errors. Return to top

+
+
+

Post Training

+
# 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))
+
+
+

Return to top

+

This part of the code saves the model weights, writes the solution to a +vtk file, prints the error values in a table, prints the time values in +a table, and saves all the arrays as numpy arrays.

+
+

save the outputs

+

All the outputs will be saved in the output directory specified in the +input file. The output directory will contain the following files: - +prediction_{epoch}.vtk : The solution file for each epoch. - +loss_function.txt : The loss function values for each epoch. - +prediction.txt : The predicted values at last epoch at the test points. +- exact.txt : The exact values at last epoch at the test points. - +error.txt : The error values at last epoch at the test points. - +time_per_epoch.txt : The time taken for each epoch. Return to +top

+
+
+

Solution Plots

+
+Exact Solution +
+

Exact Solution

+
+
+
+Predicted Solution +
+

Predicted Solution

+
+
+
+Error +
+
+
+

References

+
    +
  1. FastVPINNs: Tensor-Driven Acceleration of VPINNs for Complex +Geometries.

  2. +
+

Return to top

+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_rst/tutorials/forward_problems_2d/complex_mesh/cd2d_gear/cd2d_gear.html b/_rst/tutorials/forward_problems_2d/complex_mesh/cd2d_gear/cd2d_gear.html new file mode 100644 index 0000000..9e8b053 --- /dev/null +++ b/_rst/tutorials/forward_problems_2d/complex_mesh/cd2d_gear/cd2d_gear.html @@ -0,0 +1,914 @@ + + + + + + + Convection-Diffusion 2D Example on Circular Domain — fastvpinns 1.0.0 documentation + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Convection-Diffusion 2D Example on Circular Domain

+

This example demonstrates how to solve a Poisson equation in 2D on a +circular domain using the fastvpinns package. +All the necessary files can be found in the examples folder of the fastvpinns GitHub repository +The Poisson equation is given by

+
+\[-\epsilon \nabla^2 u + \mathbf{b} \cdot \nabla u + cu = f \quad \text{in} \quad \Omega\]
+

where (\(\Omega\)) is the circular domain and (f) is the source +term. The boundary conditions are given by

+
+\[u = 0 \quad \text{on} \quad \partial \Omega\]
+

For this problem, the parameters are

+
+\[f = 50 \sin(x) + \cos(x)\]
+
+\[\epsilon = 1\]
+
+\[\mathbf{b} = [0.1, 0]\]
+
+\[c = 0\]
+

The exact solution is computed using +ParMOON, an inhouse FEM +package.

+
+

Computational Domain

+

The computational domain is a circular domain with radius 1 centered at +(0, 0).

+
+alt text +
+
+

Contents

+ +
+
+

Steps to run the code

+

To run the code, execute the following command:

+
python3 main_cd2d_gear.py input.yaml
+
+
+
+
+

Example File - cd2d_gear_example.py

+

This file hosts all the details about the bilinear parameters for the +PDE, boundary conditions, source term, and the exact solution.

+
+

Defining the boundary conditions

+

The function get_boundary_function_dict returns a dictionary of +boundary functions. The key of the dictionary is the boundary id and the +value is the boundary function. The function get_bound_cond_dict +returns a dictionary of boundary conditions. The key of the dictionary +is the boundary id and the value is the boundary condition.

+

here inner_boundary and outer_boundary are the functions which +return the boundary values for the inner and outer boundaries of the +gear geometry. The boundary ids are defined as 1000 and 1001 +respectively. The boundary conditions are defined as “dirichlet” for +both the boundaries.

+
+Gmesh Circle +
+

For externally created geometries from gmsh, the user needs to provide +the physical tag for the boundaries present in the geometry. +In our case, we have used 1001, 1000 to define the internal and external boundary in mesh file.

+

Note : As of now, only Dirichlet boundary conditions are supported.

+
def inner_boundary(x, y):
+    """
+    This function will return the boundary value for given component of a boundary
+    """
+    return 0.0
+
+
+def outer_boundary(x, y):
+    """
+    This function will return the boundary value for given component of a boundary
+    """
+
+    return 0.0
+
+def get_boundary_function_dict():
+    """
+    This function will return a dictionary of boundary functions
+    """
+    return {1000: outer_boundary, 1001: inner_boundary}
+
+
+def get_bound_cond_dict():
+    """
+    This function will return a dictionary of boundary conditions
+    """
+    return {1000: "dirichlet", 1001: "dirichlet"}
+
+
+
+
+

Defining the source term

+

The function rhs returns the value of the source term at a given +point.

+
def rhs(x, y):
+    """
+    This function will return the value of the rhs at a given point
+    """
+    f_temp = 50 * np.sin(x) + np.cos(x)
+
+    return f_temp
+
+
+

Return to top

+
+
+

Defining the exact solution

+

The function exact_solution returns the value of the exact solution +at a given point.

+

Note :Here the exact solution function does not matter, since the +exact solution will be read externally from a file, which contains the +fem solution to the problem.

+
def exact_solution(x, y):
+    """
+    This function will return the exact solution at a given point
+    """
+    r = np.sqrt(x**2 + y**2)
+
+    return np.ones_like(x) * 0
+
+
+

Return to top

+
+
+

Defining the bilinear form

+

The function get_bilinear_params_dict returns a dictionary of +bilinear parameters. The dictionary contains the values of the +parameters \(\epsilon\) (epsilon), \(b_x\) (convection)

+

Note : If any of the bilinear parameters are not present in the +dictionary (for the cd2d model), then the code will throw an error.

+
def get_bilinear_params_dict():
+    """
+    This function will return a dictionary of bilinear parameters
+    """
+    eps = 1.0
+    b_x = 0.1
+    b_y = 0.0
+    c = 0.0
+
+    return {"eps": eps, "b_x": b_x, "b_y": b_y, "c": c}
+
+
+

Return to top

+
+
+
+

Input File

+

This is the file that contains all the details about the problem. The +input file is in the YAML format. The input file for this example is +given below. The contents of the yaml files are as follows

+
+
+
+

Experimentation

+

Defines the output path where the results will be saved.

+
experimentation:
+  output_path: "output/cd2d_gear"  # Path to the output directory where the results will be saved.
+
+
+

Return to top

+
+
+

Geometry

+

It contains the details about the geometry of the domain. The mesh +generation method can be either “internal” or “external”. If the mesh +generation method is “internal”, then the internal_mesh_params are +used to generate the mesh. If the mesh generation method is “external”, +then the mesh is read from the file specified in the mesh_file +parameter.

+
    +
  • In this case, we will use an external mesh. The mesh +../meshes/circle_quad.mesh is generated using the Gmsh software. +The mesh needs to have physical elements defined for the boundary. In +this case, the physical element is defined as 1000 (which is defined +in the circle_boundary function in the cd2d_gear_example.py +file).

  • +
  • exact_solution_generation is set to “external” which means that +the exact solution is read from an external file.

  • +
  • mesh_type is set to “quadrilateral” which means that the mesh is +a quadrilateral mesh. Note: As of now, only quadrilateral meshes are +supported.

  • +
  • boundary_refinement_level is set to 2 which means that the +boundary is refined 2 times. (i.e), when the mesh is read, only the +boundary points of an edge in quadrilateral mesh are read. this +refinement will refine the boundary points to get more boundary +points within the edge.

  • +
  • boundary_sampling_method is set to “uniform” which means that the +boundary points are sampled using the “uniform” method. (Use only +uniform sampling as of now.)

  • +
  • generate_mesh_plot is set to True which means that the mesh plot +is generated and saved in the output directory.

  • +
+
geometry:
+  mesh_generation_method: "external"
+  generate_mesh_plot: False
+  internal_mesh_params:
+    x_min: 0
+    x_max: 1
+    y_min: 0
+    y_max: 1
+    n_cells_x: 8
+    n_cells_y: 8
+    n_boundary_points: 2000
+    n_test_points_x: 100
+    n_test_points_y: 100
+
+  exact_solution:
+    exact_solution_generation: "external" # whether the exact solution needs to be read from external file.
+    exact_solution_file_name: "fem_output_gear_forward_sin.csv" # External solution file name.
+
+  mesh_type: "quadrilateral"
+  external_mesh_params:
+    mesh_file_name: "../meshes/gear.mesh"  # should be a .mesh file
+    boundary_refinement_level: 2
+    boundary_sampling_method: "uniform"  # "uniform"
+
+
+

Return to top

+
+
+

Finite Element Space

+

This section contains the details about the finite element spaces.

+
fe:
+  fe_order: 4
+  fe_type: "jacobi"
+  quad_order: 5
+  quad_type: "gauss-jacobi"
+
+
+

Here the fe_order is set to 6 which means it has 6 basis functions +in each direction. The quad_order is set to 10 which means it uses a +10-points in each direction for the quadrature rule. The supported +quadrature rules are “gauss-jacobi” and “gauss-legendre”. In this +version of code, both “jacobi” and “legendre” refer to the same basis +functions (to maintain backward compatibility). The basis functions are +special type of Jacobi polynomials defined by

+
+\[J_{n} = J_{n-1} - J_{n+1}\]
+

, where J n is the nth Jacobi polynomial.

+

Return to top

+
+
+

pde

+

This value provides the beta values for the dirichlet boundary +conditions. The beta values are the multipliers that are used to multiply +the boundary losses. $loss_{total} = loss_{pde} + beta cdot loss_{dirichlet}$

+
pde:
+  beta: 5  # Parameter for the PDE.
+
+
+

Return to top

+
+
+

model

+

The model section contains the details about the dense model to be used. +The model architecture is given by the model_architecture parameter. +The activation function used in the model is given by the activation +parameter. The epochs parameter is the number of training epochs. +The dtype parameter is the data type used for computations. The +learning_rate section contains the parameters for learning rate +scheduling. The initial_learning_rate parameter is the initial +learning rate. The use_lr_scheduler parameter is a flag indicating +whether to use the learning rate scheduler. The decay_steps +parameter is the number of steps between each learning rate decay. The +decay_rate parameter is the decay rate for the learning rate. The +staircase parameter is a flag indicating whether to use the +staircase decay.

+

Any parameter which are not mentioned above are archived parameters, +which are not used in the current version of the code. (like +use_attention, set_memory_growth)

+
model:
+  model_architecture: [2, 50,50,50, 1]
+  activation: "tanh"
+  use_attention: False
+  epochs: 150000
+  dtype: "float32"
+  set_memory_growth: False
+  learning_rate:
+    initial_learning_rate: 0.005
+    use_lr_scheduler: True
+    decay_steps: 1000
+    decay_rate: 0.99
+    staircase: False
+
+
+

Return to top

+
+
+

logging

+

update_console_output defines the epochs at which you need to log +parameters like loss, time taken, etc.

+
logging:
+  update_console_output: 10000
+
+
+

Return to top

+
+

Main File - main_cd2d.py

+

This file contains the main code to solve the Poisson equation in 2D on +a circular domain. The code reads the input file, sets up the problem, +and solves the Poisson equation using the fastvpinns package.

+
+
+
+

Importing the required libraries

+

The following libraries are imported in the main file.

+
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
+
+
+

Return to top

+
+
+

imports from fastvpinns

+

The following imports are used from the fastvpinns package.

+
    +
  • Imports the geometry module from the fastvpinns package, which +contains the Geometry_2D class responsible for setting up the +geometry of the domain.

  • +
+
from fastvpinns.Geometry.geometry_2d import Geometry_2D
+
+
+
    +
  • Imports the fespace module from the fastvpinns package, which +contains the FE class responsible for setting up the finite +element spaces.

  • +
+
from fastvpinns.FE.fespace2d import Fespace2D
+
+
+
    +
  • Imports the datahandler module from the fastvpinns package, which +contains the DataHandler class responsible for handling and +converting the data to necessary shape for training purposes

  • +
+
from fastvpinns.DataHandler.datahandler import DataHandler
+
+
+
    +
  • Imports the model module from the fastvpinns package, which +contains the Model class responsible for training the neural +network model.

  • +
+
from fastvpinns.Model.model import DenseModel
+
+
+
    +
  • Import the Loss module from the fastvpinns package, which +contains the loss function of the PDE to be solved in tensor form.

  • +
+
from fastvpinns.physics.cd2d import pde_loss_cd2d
+
+
+
    +
  • Import additional functionalities from the fastvpinns package.

  • +
+
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
+
+
+

Return to top

+
+
+

Reading the input file

+

The input file is read using the yaml library.

+
if len(sys.argv) != 2:
+        print("Usage: python main.py <input file>")
+        sys.exit(1)
+
+    # Read the YAML file
+    with open(sys.argv[1], 'r') as f:
+        config = yaml.safe_load(f)
+
+
+
+
+

Reading all input parameters

+
# 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_console_output = config['logging']['update_console_output']
+
+
+

all the variables which are named with the prefix i_ are input +parameters which are read from the input file. Return to +top

+
+
+

Set up the geometry

+

Obtain the bounndary condition and boundary values from the +cd2d_gear_example.py file and initialise the Geometry_2D class. +After that use the domain.read_mesh functionality to read the +external mesh file.

+
cells, boundary_points = domain.read_mesh(
+        i_mesh_file_name,
+        i_boundary_refinement_level,
+        i_boundary_sampling_method,
+        refinement_level=1,
+    )
+
+
+

Return to top

+
+
+

Setup fespace

+

Initialise the Fespace2D class with the required parameters.

+
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,
+    )
+
+
+

Return to top

+
+
+

Setup datahandler

+

Initialise the DataHandler class with the required parameters.

+
datahandler = DataHandler2D(fespace, domain, dtype=i_dtype)
+
+
+

Return to top

+
+
+

Setup model

+

Setup the necessary parameters for the model and initialise the Model +class. Before that fill the params dictionary with the required +parameters.

+
model = DenseModel(
+        layer_dims=i_model_architecture,
+        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,
+    )
+
+
+

Return to top

+
+
+

Pre-train setup

+
if i_exact_solution_generation == "internal":
+  y_exact = exact_solution(test_points[:, 0], test_points[:, 1])
+else:
+  exact_db = pd.read_csv(f"{i_exact_solution_file_name}", header=None, delimiter=",")
+  y_exact = exact_db.iloc[:, 2].values.reshape(-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)
+
+
+

Here the exact solution is being read from the external file. The +external solution at the test points is computed by FEM and stored in a +csv file. This sets up the test points and the exact solution. The +progress bar is initialised and the loss arrays are set up. The beta +value is set up as a constant tensor. Return to top

+
+
+

Training

+
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'])
+
+
+

This train_step function trains the model for one epoch and returns +the loss. The loss is appended to the loss array. Then for every epoch +where +(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}"
+)
+
+
+

We will compute all the test errors and write the solution to a vtk file +for a complex mesh. Further, the console output will be printed with the +loss values and the test errors. Return to top

+
+
+

Post Training

+
# 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))
+
+
+

Return to top

+

This part of the code saves the model weights, writes the solution to a +vtk file, prints the error values in a table, prints the time values in +a table, and saves all the arrays as numpy arrays.

+
+

save the outputs

+

All the outputs will be saved in the output directory specified in the +input file. The output directory will contain the following files: - +prediction_{epoch}.vtk : The solution file for each epoch. - +loss_function.txt : The loss function values for each epoch. - +prediction.txt : The predicted values at last epoch at the test points. +- exact.txt : The exact values at last epoch at the test points. - +error.txt : The error values at last epoch at the test points. - +time_per_epoch.txt : The time taken for each epoch. Return to +top

+
+
+

Solution Plots

+
+Exact Solution +
+

Exact Solution

+
+
+
+Predicted Solution +
+

Predicted Solution

+
+
+
+Error +
+

Error

+
+
+
+
+

References

+
    +
  1. FastVPINNs: Tensor-Driven Acceleration of VPINNs for Complex +Geometries.

  2. +
+

Return to top

+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_rst/tutorials/forward_problems_2d/complex_mesh/helmholtz2d/helmholtz2d.html b/_rst/tutorials/forward_problems_2d/complex_mesh/helmholtz2d/helmholtz2d.html new file mode 100644 index 0000000..9311c25 --- /dev/null +++ b/_rst/tutorials/forward_problems_2d/complex_mesh/helmholtz2d/helmholtz2d.html @@ -0,0 +1,909 @@ + + + + + + + Helmholtz 2D Example on Circular Domain — fastvpinns 1.0.0 documentation + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Helmholtz 2D Example on Circular Domain

+

This example demonstrates how to solve a Poisson equation in 2D on a +circular domain using the fastvpinns package. +All the necessary files can be found in the examples folder of the fastvpinns GitHub repository

+

The Poisson equation is given by

+
+\[-\epsilon \nabla^2 u + k^2u = f \quad \text{in} \quad \Omega\]
+

where (\(\Omega\)) is the circular domain and (f) is the source +term. The boundary conditions are given by

+
+\[u = (x + y) * sin(\pi * x) * sin(\pi * y) \quad \text{on} \quad \partial \Omega\]
+

For this problem, the parameters are

+
+\[\begin{split}f = 2 \pi \cos(\pi y) \sin(\pi x) + 2 \pi \cos(\pi x) \sin(\pi y) + (x+y) \sin(\pi x) \sin(\pi y) - \\ +2 \pi^2 (x+y) \sin(\pi x) \sin(\pi y)\end{split}\]
+
+\[\epsilon = 1.0\]
+
+\[k = 1.0\]
+

The exact solution is given by

+
+\[u = (x + y) * sin(\pi * x) * sin(\pi * y)\]
+
+

Computational Domain

+

The computational domain is a circular domain with radius 1 centered at +(0, 0).

+
+alt text +
+
+

Contents

+ +
+
+

Steps to run the code

+

To run the code, execute the following command:

+
python3 main_helmholtz.py input.yaml
+
+
+
+
+

Example File - helmholtz_example.py

+

This file hosts all the details about the bilinear parameters for the +PDE, boundary conditions, source term, and the exact solution.

+
+

Defining the boundary conditions

+

The function circle_boundary returns the boundary value for a given +component of the boundary. The function get_boundary_function_dict +returns a dictionary of boundary functions. The key of the dictionary is +the boundary id and the value is the boundary function. The function +get_bound_cond_dict returns a dictionary of boundary conditions. The +key of the dictionary is the boundary id and the value is the boundary +condition.

+
+Unit Circle +
+

For externally created geometries from gmsh, the user needs to provide +the physical tag for the boundaries present in the geometry. +In our case, we have used 1000 to define the circular boundary in mesh file.

+

Note : As of now, only Dirichlet boundary conditions are supported.

+
def circle_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 get_boundary_function_dict():
+    """
+    This function will return a dictionary of boundary functions
+    """
+    return {1000: circle_boundary}
+
+
+def get_bound_cond_dict():
+    """
+    This function will return a dictionary of boundary conditions
+    """
+    return {1000: "dirichlet"}
+
+
+
+
+

Defining the source term

+

The function rhs returns the value of the source term at a given +point.

+
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
+
+
+

Return to top

+
+
+

Defining the exact solution

+

The function exact_solution returns the value of the exact solution +at a given point.

+
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)
+
+
+

Return to top

+
+
+

Defining the bilinear form

+

The function get_bilinear_params_dict returns a dictionary of +bilinear parameters. The dictionary contains the values of the +parameters (\(\epsilon\)), (b_x), (b_y), and (c).

+

Note : If any of the bilinear parameters are not present in the +dictionary (for the cd2d model), then the code will throw an error.

+
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}
+
+
+

Return to top

+
+
+
+

Input File

+

This is the file that contains all the details about the problem. The +input file is in the YAML format. The input file for this example is +given below. The contents of the yaml files are as follows

+
+
+
+

Experimentation

+

Defines the output path where the results will be saved.

+
experimentation:
+  output_path: "output/helmholtz/1"
+
+
+

Return to top

+
+
+

Geometry

+

It contains the details about the geometry of the domain. The mesh +generation method can be either “internal” or “external”. If the mesh +generation method is “internal”, then the internal_mesh_params are +used to generate the mesh. If the mesh generation method is “external”, +then the mesh is read from the file specified in the mesh_file +parameter.

+
    +
  • In this case, we will use an external mesh. The mesh +../meshes/circle_quad.mesh is generated using the Gmsh software. +The mesh needs to have physical elements defined for the boundary. In +this case, the physical element is defined as 1000 (which is defined +in the circle_boundary function in the helmholtz_example.py +file).

  • +
  • exact_solution_generation is set to “internal” which means that +the exact solution is generated using the exact_solution function +in the helmholtz_example.py file. For external check the other +examples cd2d_gear

  • +
  • mesh_type is set to “quadrilateral” which means that the mesh is +a quadrilateral mesh. Note: As of now, only quadrilateral meshes are +supported.

  • +
  • boundary_refinement_level is set to 4 which means that the +boundary is refined 4 times. (i.e), when the mesh is read, only the +boundary points of an edge in quadrilateral mesh are read. this +refinement will refine the boundary points to get more boundary +points within the edge.

  • +
  • boundary_sampling_method is set to “uniform” which means that the +boundary points are sampled using the “uniform” method. (Use only +uniform sampling as of now.)

  • +
  • generate_mesh_plot is set to True which means that the mesh plot +is generated and saved in the output directory.

  • +
+
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: "internal" # 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".
+
+
+

Return to top

+
+
+

Finite Element Space

+

This section contains the details about the finite element spaces.

+
fe:
+  fe_order: 4 # Order of the finite element basis functions.
+  fe_type: "jacobi"  # Type of finite element basis functions.
+  quad_order: 5  # Order of the quadrature rule.
+  quad_type: "gauss-jacobi"  # Type of quadrature rule.
+
+
+

Here the fe_order is set to 6 which means it has 6 basis functions +in each direction. The quad_order is set to 10 which means it uses a +10-points in each direction for the quadrature rule. The supported +quadrature rules are “gauss-jacobi” and “gauss-legendre”. In this +version of code, both “jacobi” and “legendre” refer to the same basis +functions (to maintain backward compatibility). The basis functions are +special type of Jacobi polynomials defined by

+
+\[J_{n} = J_{n-1} - J_{n+1}\]
+

, where J n is the nth Jacobi polynomial.

+

Return to top

+
+
+

pde

+

This value provides the beta values for the Dirichlet boundary conditions. The beta values are the multipliers that are used to multiply the boundary losses. The total loss is calculated as follows:

+
+\[loss_{total} = loss_{pde} + \beta \cdot loss_{dirichlet}\]
+
pde:
+  beta: 10 # Parameter for the PDE.
+
+
+

Return to top

+
+
+

model

+

The model section contains the details about the dense model to be used. +The model architecture is given by the model_architecture parameter. +The activation function used in the model is given by the activation +parameter. The epochs parameter is the number of training epochs. +The dtype parameter is the data type used for computations. The +learning_rate section contains the parameters for learning rate +scheduling. The initial_learning_rate parameter is the initial +learning rate. The use_lr_scheduler parameter is a flag indicating +whether to use the learning rate scheduler. The decay_steps +parameter is the number of steps between each learning rate decay. The +decay_rate parameter is the decay rate for the learning rate. The +staircase parameter is a flag indicating whether to use the +staircase decay.

+

Any parameter which are not mentioned above are archived parameters, +which are not used in the current version of the code. (like +use_attention, set_memory_growth)

+
model:
+  model_architecture: [2, 30,30,30, 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.
+
+
+

Return to top

+
+
+

logging

+

update_console_output defines the epochs at which you need to log +parameters like loss, time taken, etc.

+
logging:
+  update_console_output: 5000
+
+
+

Return to top

+
+

Main File - main_helmholtz.py

+

This file contains the main code to solve the Poisson equation in 2D on +a circular domain. The code reads the input file, sets up the problem, +and solves the Poisson equation using the fastvpinns package.

+
+
+
+

Importing the required libraries

+

The following libraries are imported in the main file.

+
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
+
+
+

Return to top

+
+
+

imports from fastvpinns

+

The following imports are used from the fastvpinns package.

+
    +
  • Imports the geometry module from the fastvpinns package, which +contains the Geometry_2D class responsible for setting up the +geometry of the domain.

  • +
+
from fastvpinns.Geometry.geometry_2d import Geometry_2D
+
+
+
    +
  • Imports the fespace module from the fastvpinns package, which +contains the FE class responsible for setting up the finite +element spaces.

  • +
+
from fastvpinns.FE.fespace2d import Fespace2D
+
+
+
    +
  • Imports the datahandler module from the fastvpinns package, which +contains the DataHandler class responsible for handling and +converting the data to necessary shape for training purposes

  • +
+
from fastvpinns.DataHandler.datahandler import DataHandler
+
+
+
    +
  • Imports the model module from the fastvpinns package, which +contains the Model class responsible for training the neural +network model.

  • +
+
from fastvpinns.Model.model import DenseModel
+
+
+
    +
  • Import the Loss module from the fastvpinns package, which +contains the loss function of the PDE to be solved in tensor form.

  • +
+
from fastvpinns.physics.helmholtz2d import pde_loss_helmholtz
+
+
+
    +
  • Import additional functionalities from the fastvpinns package.

  • +
+
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
+
+
+

Return to top

+
+
+

Reading the input file

+

The input file is read using the yaml library.

+
if len(sys.argv) != 2:
+        print("Usage: python main.py <input file>")
+        sys.exit(1)
+
+    # Read the YAML file
+    with open(sys.argv[1], 'r') as f:
+        config = yaml.safe_load(f)
+
+
+
+
+

Reading all input parameters

+
# 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_console_output = config['logging']['update_console_output']
+
+
+

all the variables which are named with the prefix i_ are input +parameters which are read from the input file. Return to +top

+
+
+

Set up the geometry

+

Obtain the bounndary condition and boundary values from the +helmholtz_example.py file and initialise the Geometry_2D class. +After that use the domain.read_mesh functionality to read the +external mesh file.

+
cells, boundary_points = domain.read_mesh(
+        i_mesh_file_name,
+        i_boundary_refinement_level,
+        i_boundary_sampling_method,
+        refinement_level=1,
+    )
+
+
+

Return to top

+
+
+

Setup fespace

+

Initialise the Fespace2D class with the required parameters.

+
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,
+    )
+
+
+

Return to top

+
+
+

Setup datahandler

+

Initialise the DataHandler class with the required parameters.

+
datahandler = DataHandler2D(fespace, domain, dtype=i_dtype)
+
+
+

Return to top

+
+
+

Setup model

+

Setup the necessary parameters for the model and initialise the Model +class. Before that fill the params dictionary with the required +parameters.

+
model = DenseModel(
+        layer_dims=i_model_architecture,
+        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,
+    )
+
+
+

Return to top

+
+
+

Pre-train setup

+
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)
+
+
+

Here the exact solution is being read from the external file. The +external solution at the test points is computed by FEM and stored in a +csv file. This sets up the test points and the exact solution. The +progress bar is initialised and the loss arrays are set up. The beta +value is set up as a constant tensor. Return to top

+
+
+

Training

+
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'])
+
+
+

This train_step function trains the model for one epoch and returns +the loss. The loss is appended to the loss array. Then for every epoch +where +(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}"
+)
+
+
+

We will compute all the test errors and write the solution to a vtk file +for a complex mesh. Further, the console output will be printed with the +loss values and the test errors. Return to top

+
+
+

Post Training

+
# 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))
+
+
+

Return to top

+

This part of the code saves the model weights, writes the solution to a +vtk file, prints the error values in a table, prints the time values in +a table, and saves all the arrays as numpy arrays.

+
+

save the outputs

+

All the outputs will be saved in the output directory specified in the +input file. The output directory will contain the following files: - +prediction_{epoch}.vtk : The solution file for each epoch. - +loss_function.txt : The loss function values for each epoch. - +prediction.txt : The predicted values at last epoch at the test points. +- exact.txt : The exact values at last epoch at the test points. - +error.txt : The error values at last epoch at the test points. - +time_per_epoch.txt : The time taken for each epoch.

+

Return to top

+
+
+

Solution Plots

+
+Exact Solution +
+

Exact Solution

+
+
+
+Predicted Solution +
+

Predicted Solution

+
+
+
+Error +
+

Error

+
+
+
+
+

References

+
    +
  1. FastVPINNs: Tensor-Driven Acceleration of VPINNs for Complex +Geometries.

  2. +
+

Return to top

+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_rst/tutorials/forward_problems_2d/complex_mesh/poisson2d/poisson2d.html b/_rst/tutorials/forward_problems_2d/complex_mesh/poisson2d/poisson2d.html new file mode 100644 index 0000000..3d5f24f --- /dev/null +++ b/_rst/tutorials/forward_problems_2d/complex_mesh/poisson2d/poisson2d.html @@ -0,0 +1,895 @@ + + + + + + + Poisson 2D Example on Circular Domain — fastvpinns 1.0.0 documentation + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Poisson 2D Example on Circular Domain

+

This example demonstrates how to solve a Poisson equation in 2D on a +circular domain using the fastvpinns package. +All the necessary files can be found in the examples folder of the fastvpinns GitHub repository

+

The Poisson equation is given by

+
+\[-\epsilon \nabla^2 u = f \quad \text{in} \quad \Omega\]
+

where (\(\Omega\)) is the circular domain and (f) is the source +term. The boundary conditions are given by

+
+\[u = -1.0 * sin( 2 \pi x) * sin( 2 \pi y) \quad \text{on} \quad \partial \Omega\]
+

For this problem, the parameters are

+
+\[f = -2.0 \cdot (2 \pi x) \cdot (\sin(2 \pi x) \cdot \sin(2 \pi y))\]
+
+\[\epsilon = 1\]
+

The exact solution is given by

+
+\[u = -1.0 * sin( 2 \pi x) * sin( 2 \pi y)\]
+
+

Computational Domain

+

The computational domain is a circular domain with radius 1 centered at +(0, 0).

+
+alt text +
+
+

Contents

+ +
+
+

Steps to run the code

+

To run the code, execute the following command:

+
python3 main_poisson2d.py input.yaml
+
+
+
+
+

Example File - sin_cos.py

+

This file hosts all the details about the bilinear parameters for the +PDE, boundary conditions, source term, and the exact solution.

+
+

Defining the boundary conditions

+

The function circle_boundary returns the boundary value for a given +component of the boundary. The function get_boundary_function_dict +returns a dictionary of boundary functions. The key of the dictionary is +the boundary id and the value is the boundary function. The function +get_bound_cond_dict returns a dictionary of boundary conditions. The +key of the dictionary is the boundary id and the value is the boundary +condition.

+
+Unit Circle +
+

For externally created geometries from gmsh, the user needs to provide +the physical tag for the boundaries present in the geometry. +In our case, we have used 1000 to define the circular boundary in mesh file.

+

Note : As of now, only Dirichlet boundary conditions are supported.

+
def circle_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 get_boundary_function_dict():
+    """
+    This function will return a dictionary of boundary functions
+    """
+    return {1000: circle_boundary}
+
+def get_bound_cond_dict():
+    """
+    This function will return a dictionary of boundary conditions
+    """
+    return {1000: "dirichlet"}
+
+
+
+
+

Defining the source term

+

The function rhs returns the value of the source term at a given +point.

+
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
+
+
+

Return to top

+
+
+

Defining the exact solution

+

The function exact_solution returns the value of the exact solution +at a given point.

+
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
+
+
+

Return to top

+
+
+

Defining the bilinear form

+

The function get_bilinear_params_dict returns a dictionary of +bilinear parameters. The dictionary contains the values of the +parameters \(\epsilon\) (diffusion coefficient).

+

Note : If any of the bilinear parameters are not present in the +dictionary (for the cd2d model), then the code will throw an error.

+
def get_bilinear_params_dict():
+    """
+    This function will return a dictionary of bilinear parameters
+    """
+    eps = 1.0
+
+    return {"eps": eps}
+
+
+

Return to top

+
+
+
+

Input File

+

This is the file that contains all the details about the problem. The +input file is in the YAML format. The input file for this example is +given below. The contents of the yaml files are as follows

+
+
+
+

Experimentation

+

Defines the output path where the results will be saved.

+
experimentation:
+  output_path: "output/helmholtz/1"
+
+
+

Return to top

+
+
+

Geometry

+

It contains the details about the geometry of the domain. The mesh +generation method can be either “internal” or “external”. If the mesh +generation method is “internal”, then the internal_mesh_params are +used to generate the mesh. If the mesh generation method is “external”, +then the mesh is read from the file specified in the mesh_file +parameter.

+
    +
  • In this case, we will use an external mesh. The mesh +../meshes/circle_quad.mesh is generated using the Gmsh software. +The mesh needs to have physical elements defined for the boundary. In +this case, the physical element is defined as 1000 (which is defined +in the circle_boundary function in the sin_cos.py file).

  • +
  • exact_solution_generation is set to “internal” which means that +the exact solution is generated using the exact_solution function +in the sin_cos.py file. For external check the other examples +cd2d_gear

  • +
  • mesh_type is set to “quadrilateral” which means that the mesh is +a quadrilateral mesh. Note: As of now, only quadrilateral meshes are +supported.

  • +
  • boundary_refinement_level is set to 4 which means that the +boundary is refined 4 times. (i.e), when the mesh is read, only the +boundary points of an edge in quadrilateral mesh are read. this +refinement will refine the boundary points to get more boundary +points within the edge.

  • +
  • boundary_sampling_method is set to “uniform” which means that the +boundary points are sampled using the “uniform” method. (Use only +uniform sampling as of now.)

  • +
  • generate_mesh_plot is set to True which means that the mesh plot +is generated and saved in the output directory.

  • +
+
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: "internal" # 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".
+
+
+

Return to top

+
+
+

Finite Element Space

+

This section contains the details about the finite element spaces.

+
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.
+
+
+

Here the fe_order is set to 6 which means it has 6 basis functions +in each direction. The quad_order is set to 10 which means it uses a +10-points in each direction for the quadrature rule. The supported +quadrature rules are “gauss-jacobi” and “gauss-legendre”. In this +version of code, both “jacobi” and “legendre” refer to the same basis +functions (to maintain backward compatibility). The basis functions are +special type of Jacobi polynomials defined by

+
+\[J_{n} = J_{n-1} - J_{n+1}\]
+

, where J n is the nth Jacobi polynomial.

+

Return to top

+
+
+

pde

+

This value provides the beta values for the Dirichlet boundary conditions. The beta values are the multipliers that are used to multiply the boundary losses. The total loss is calculated as the sum of the PDE loss and the Dirichlet boundary loss, weighted by the beta values:

+
+\[loss_{total} = loss_{pde} + \beta \cdot loss_{dirichlet}\]
+
pde:
+  beta: 10 # Parameter for the PDE.
+
+
+

Return to top

+
+
+

model

+

The model section contains the details about the dense model to be used. +The model architecture is given by the model_architecture parameter. +The activation function used in the model is given by the activation +parameter. The epochs parameter is the number of training epochs. +The dtype parameter is the data type used for computations. The +learning_rate section contains the parameters for learning rate +scheduling. The initial_learning_rate parameter is the initial +learning rate. The use_lr_scheduler parameter is a flag indicating +whether to use the learning rate scheduler. The decay_steps +parameter is the number of steps between each learning rate decay. The +decay_rate parameter is the decay rate for the learning rate. The +staircase parameter is a flag indicating whether to use the +staircase decay.

+

Any parameter which are not mentioned above are archived parameters, +which are not used in the current version of the code. (like +use_attention, set_memory_growth)

+
model:
+  model_architecture: [2, 30, 30, 30, 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: 5000  # 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.
+
+
+

Return to top

+
+
+

logging

+

update_console_output defines the epochs at which you need to log +parameters like loss, time taken, etc.

+
logging:
+  update_console_output: 2000
+
+
+

Return to top

+
+

Main File - main_poisson2d.py

+

This file contains the main code to solve the Poisson equation in 2D on +a circular domain. The code reads the input file, sets up the problem, +and solves the Poisson equation using the fastvpinns package.

+
+
+
+

Importing the required libraries

+

The following libraries are imported in the main file.

+
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
+
+
+

Return to top

+
+
+

imports from fastvpinns

+

The following imports are used from the fastvpinns package.

+
    +
  • Imports the geometry module from the fastvpinns package, which +contains the Geometry_2D class responsible for setting up the +geometry of the domain.

  • +
+
from fastvpinns.Geometry.geometry_2d import Geometry_2D
+
+
+
    +
  • Imports the fespace module from the fastvpinns package, which +contains the FE class responsible for setting up the finite +element spaces.

  • +
+
from fastvpinns.FE.fespace2d import Fespace2D
+
+
+
    +
  • Imports the datahandler module from the fastvpinns package, which +contains the DataHandler class responsible for handling and +converting the data to necessary shape for training purposes

  • +
+
from fastvpinns.DataHandler.datahandler import DataHandler
+
+
+
    +
  • Imports the model module from the fastvpinns package, which +contains the Model class responsible for training the neural +network model.

  • +
+
from fastvpinns.Model.model import DenseModel
+
+
+
    +
  • Import the Loss module from the fastvpinns package, which +contains the loss function of the PDE to be solved in tensor form.

  • +
+
from fastvpinns.physics.helmholtz2d import pde_loss_helmholtz
+
+
+
    +
  • Import additional functionalities from the fastvpinns package.

  • +
+
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
+
+
+

Return to top

+
+
+

Reading the input file

+

The input file is read using the yaml library.

+
if len(sys.argv) != 2:
+        print("Usage: python main.py <input file>")
+        sys.exit(1)
+
+    # Read the YAML file
+    with open(sys.argv[1], 'r') as f:
+        config = yaml.safe_load(f)
+
+
+
+
+

Reading all input parameters

+
# 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_console_output = config['logging']['update_console_output']
+
+
+

all the variables which are named with the prefix i_ are input +parameters which are read from the input file. Return to +top

+
+
+

Set up the geometry

+

Obtain the bounndary condition and boundary values from the +sin_cos.py file and initialise the Geometry_2D class. After that +use the domain.read_mesh functionality to read the external mesh +file.

+
cells, boundary_points = domain.read_mesh(
+        i_mesh_file_name,
+        i_boundary_refinement_level,
+        i_boundary_sampling_method,
+        refinement_level=1,
+    )
+
+
+

Return to top

+
+
+

Setup fespace

+

Initialise the Fespace2D class with the required parameters.

+
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,
+    )
+
+
+

Return to top

+
+
+

Setup datahandler

+

Initialise the DataHandler class with the required parameters.

+
datahandler = DataHandler2D(fespace, domain, dtype=i_dtype)
+
+
+

Return to top

+
+
+

Setup model

+

Setup the necessary parameters for the model and initialise the Model +class. Before that fill the params dictionary with the required +parameters.

+
model = DenseModel(
+        layer_dims=i_model_architecture,
+        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,
+    )
+
+
+

Return to top

+
+
+

Pre-train setup

+
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)
+
+
+

Here the exact solution is being read from the external file. The +external solution at the test points is computed by FEM and stored in a +csv file. This sets up the test points and the exact solution. The +progress bar is initialised and the loss arrays are set up. The beta +value is set up as a constant tensor. Return to top

+
+
+

Training

+
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'])
+
+
+

This train_step function trains the model for one epoch and returns +the loss. The loss is appended to the loss array. Then for every epoch +where +(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}"
+)
+
+
+

We will compute all the test errors and write the solution to a vtk file +for a complex mesh. Further, the console output will be printed with the +loss values and the test errors. Return to top

+
+
+

Post Training

+
# 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))
+
+
+

Return to top

+

This part of the code saves the model weights, writes the solution to a +vtk file, prints the error values in a table, prints the time values in +a table, and saves all the arrays as numpy arrays.

+
+

save the outputs

+

All the outputs will be saved in the output directory specified in the +input file. The output directory will contain the following files: - +prediction_{epoch}.vtk : The solution file for each epoch. - +loss_function.txt : The loss function values for each epoch. - +prediction.txt : The predicted values at last epoch at the test points. +- exact.txt : The exact values at last epoch at the test points. - +error.txt : The error values at last epoch at the test points. - +time_per_epoch.txt : The time taken for each epoch.

+

Return to top

+
+
+

Solution Plots

+Exact Solution +Predicted Solution +Error +
+
+

References

+
    +
  1. FastVPINNs: Tensor-Driven Acceleration of VPINNs for Complex +Geometries.

  2. +
+

Return to top

+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_rst/tutorials/forward_problems_2d/hard_boundary_constraints/poisson_2d/poisson2d_hard.html b/_rst/tutorials/forward_problems_2d/hard_boundary_constraints/poisson_2d/poisson2d_hard.html new file mode 100644 index 0000000..19bc7d2 --- /dev/null +++ b/_rst/tutorials/forward_problems_2d/hard_boundary_constraints/poisson_2d/poisson2d_hard.html @@ -0,0 +1,508 @@ + + + + + + + Solving forward problems with FastVPINNs : Enforcing hard boundary constraints with an ansatz function. — fastvpinns 1.0.0 documentation + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Solving forward problems with FastVPINNs : Enforcing hard boundary constraints with an ansatz function.

+

In this example, we will learn how to use hard boundary constraints using FastVPINNs. +All the necessary files can be found in the examples folder of the fastvpinns GitHub repository

+
+\[-\epsilon\Delta u(x) = f(x), \quad \ x \in \Omega = (-1, 1)^2\]
+

where

+
+\[f(x,y) = -2\omega^2\sin{\omega x}\sin{\omega y}\]
+

We begin by introducing the various files required to run this example

+
+

Contents

+ +

The code in this example can be run using

+
python3 main_poisson2d_hard.py input.yaml
+
+
+
+
+

Example File

+

The example file, sin_cos.py, defines the boundary conditions and +boundary values, the forcing function and exact function (if test error +needs to be calculated), bilinear parameters and the actual value of the +parameter that needs to be estimated (if the error between the actual +and estimated parameter needs to be calculated)

+
+

Defining boundary

+

values Since this example enforces zero Dirichlet boundary conditions +using hard constraints, the boundary functions defined in the example +file are not used. Instead, the ansatz function for hard boundary +constraints is defined in the main file

+
+Unit Square +
+

For internally generated geometries, the boundary id’s will be hardcoded to +1000 for bottom, 1001 for right, 1002 for top, and 1003 for left; as shown in figure.

+
+
+

Defining the forcing function

+

rhs can be used to define the forcing function \(f\).

+
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
+
+
+
+
+

Defining bilinear parameters

+

The bilinear parameters like diffusion constant can be defined by +get_bilinear_params_dict

+
def get_bilinear_params_dict():
+    """
+    This function will return a dictionary of bilinear parameters
+    """
+    eps = 1.0
+
+    return {"eps": eps}
+
+
+

Here, eps denoted the diffusion constant.

+

Back to Contents

+
+
+
+

Input file

+

The input file, input_inverse.yaml, is used to define inputs to your +solver. These will usually parameters that will changed often throughout +your experimentation, hence it is best practice to pass these parameters +externally. The input file is divided based on the modules which use the +parameter in question, as follows - #``experimentation`` This +contains output_path, a string which specifies which folder will be +used to store your outputs.

+
+

geometry

+

This section defines the geometrical parameters for your domain. 1. In +this example, we set the mesh_generation_method as "internal". +This generates a regular quadrilateral domain with a uniform mesh. 2. +The parameters in internal_mesh_params define the x and y limits of +the quadrilateral domain(xmin, xmax, ymin and ymax), +number of cells in the domain in the x and y direction (n_cells_x +and n_cells_y), number of total boundary points +(n_boundary_points) and number of test points in x and y direction +(n_test_points_x and n_test_points_y). 3. mesh_type : +FastVPINNs currently provides support for quadrilateral elements only. +4. external_mesh_params can be used to specify parameters for the +external mesh, and can be ignored for this example

+
+
+

fe

+

The parameters related to the finite element space are defined here. 1. +fe_order sets the order of the finite element test functions. 2. +fe_type set which type of polynomial will be used as the finite +element test function. 3. quad_order is the number of quadrature in +each direction in each cell. Thus the total number of quadrature points +in each cell will be quad_order\(^2\) 4. quad_type +specifies the quadrature rule to be used.

+
+
+

pde

+

beta specifies the weight by which the boundary loss will be +multiplied before being added to the PDE loss.

+
+
+

model

+

The parameters pertaining to the neural network are specified here. 1. +model_architecture is used to specify the dimensions of the neural +network. In this example, [2, 30, 30, 30, 1] corresponds to a neural +network with 2 inputs (for a 2-dimensional problem), 1 output (for a +scalar problem) and 3 hidden layers with 30 neurons each. 2. +activation specifies the activation function to be used. 3. +use_attention specifies if attnention layers are to be used in the +model. This feature is currently under development and hence should be +set to false for now. 4. epochs is the number of iterations for +which the network must be trained. 5. dtype specifies which datatype +(float32 or float64) will be used for the tensor calculations. +6. set_memory_growth, when set to True will enable tensorflow’s +memory growth function, restricting the memory usage on the GPU. This is +currently under development and must be set to False for now. 7. +learning_rate sets the learning rate initial_learning_rate if a +constant learning rate is used. A learning rate scheduler can be used by +toggling use_lr_scheduler to True and setting the corresponding +decay parameters below it.

+
+
+

logging

+

It specifies the frequency with which the progress bar and console +output will be updated, and at what interval will inference be carried +out to print the solution image in the output folder.

+

Back to contents

+
+
+
+

Main file

+

This is the main file which needs to be run for the experiment, with the +input file as an argument. For the example, we will use the main file +main_poisson2d_hard.py

+

Following are the key components of a FastVPINNs main file

+
+

Import relevant FastVPINNs methods

+
from fastvpinns.data.datahandler2d import DataHandler2D
+from fastvpinns.FE.fespace2d import Fespace2D
+from fastvpinns.Geometry.geometry_2d import Geometry_2D
+
+
+

Will import the functions related to setting up the finite element +space, 2D Geometry and the datahandler required to manage data and make +it available to the model.

+
from fastvpinns.model.model_hard import DenseModel_Hard
+
+
+

Will import the model file where the neural network and its training +function is defined. The model file model_hard.py contains the +DenseModel_Hard class. The call function in this model applies +the hard boundary constraint function to the output of the neural +network, and the train_step function does not add a supervised +boundary loss to the PDE residual for training.

+
from fastvpinns.physics.poisson2d import pde_loss_poisson
+
+
+

Imports the loss function for the 2-dimensional Poisson problem.

+
from fastvpinns.utils.compute_utils import compute_errors_combined
+from fastvpinns.utils.plot_utils import plot_contour, plot_loss_function, plot_test_loss_function
+from fastvpinns.utils.print_utils import print_table
+
+
+

Imports functions to calculate the loss, plot the results and print +outputs to the console.

+
+
+

Reading the Input File

+

The input file is loaded into config and the input parameters are +read and assigned to their respective variables.

+
+
+

Setting up 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)
+
+
+

will instantiate a Geometry_2D object, domain, with the mesh +type, mesh generation method and test points. In our example, the mesh +generation method is internal, so the cells and boundary points will +be obtained using the generate_quad_mesh_internal method.

+
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,
+)
+
+
+
+
+

Reading the boundary conditions and values

+

As explained in the example file section, the +boundary conditions and values are read as a dictionary from the example +file

+
bound_function_dict, bound_condition_dict = get_boundary_function_dict(), get_bound_cond_dict()
+
+
+
+
+

Setting up the finite element space

+
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,
+)
+
+
+

fespace will contain all the information about the finite element +space, including those read from the input file

+
+
+

Defining the hard boundary constraint ansatz

+

The ansatz function for applying zero Dirichlet hard boundary contraints +can be defined using apply_hard_boundary_constraints

+
@tf.function
+def apply_hard_boundary_constraints(inputs, x):
+    """This method applies hard boundary constraints to the model.
+    :param inputs: Input tensor
+    :type inputs: tf.Tensor
+    :param x: Output tensor from the model
+    :type x: tf.Tensor
+    :return: Output tensor with hard boundary constraints
+    :rtype: tf.Tensor
+    """
+    ansatz = (
+        tf.tanh(4.0 * np.pi * inputs[:, 0:1])
+        * tf.tanh(4.0 * np.pi * inputs[:, 1:2])
+        * tf.tanh(4.0 * np.pi * (inputs[:, 0:1] - 1.0))
+        * tf.tanh(4.0 * np.pi * (inputs[:, 1:2] - 1.0))
+    )
+    ansatz = tf.cast(ansatz, i_dtype)
+    return ansatz * x
+
+
+

Here, the ansatz we use is of the form +\(\tanh{(4\pi x)}\times\tanh{(4\pi(x-1))}\times\tanh{(4\pi y)}\times\tanh{(4\pi(y-1))}\)

+
+
+

Instantiating a model with hard boundary constraints

+
model = DenseModel_Hard(
+    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,
+    hard_constraint_function=apply_hard_boundary_constraints,
+)
+
+
+

DenseModel_Hard is a model written for inverse problems with +spatially varying parameter estimation. In this problem, we pass the +loss function pde_loss_poisson from the physics file +poisson2d.py.

+
+
+

Training the model

+

We are now ready to train the model to approximate the solution of the +PDE.

+
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)
+        ...
+
+
+

Back to contents

+
+
+
+

Solution

+
+Exact Solution +
+

Exact Solution

+
+
+
+Predicted Solution +
+

Predicted Solution

+
+
+
+Error +
+

Error

+
+
+
+
+

References

+
    +
  1. FastVPINNs: Tensor-Driven Acceleration of VPINNs for Complex +Geometries.

  2. +
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_rst/tutorials/forward_problems_2d/uniform_mesh/helmholtz_2d/helmholtz2d_uniform.html b/_rst/tutorials/forward_problems_2d/uniform_mesh/helmholtz_2d/helmholtz2d_uniform.html new file mode 100644 index 0000000..a25c09f --- /dev/null +++ b/_rst/tutorials/forward_problems_2d/uniform_mesh/helmholtz_2d/helmholtz2d_uniform.html @@ -0,0 +1,482 @@ + + + + + + + Solving forward problems with FastVPINNs : Helmholtz - 2D — fastvpinns 1.0.0 documentation + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Solving forward problems with FastVPINNs : Helmholtz - 2D

+

In this example, we will learn to solve the Helmholtz equation in 2D +All the necessary files can be found in the examples folder of the fastvpinns GitHub repository

+
+\[-\epsilon\Delta u(x) + k^2 u = f(x), \quad \ x \in \Omega = (-1, 1)^2\]
+

where

+
+\[\begin{split}f(x,y) = 2 \pi cos(\pi y)sin(\pi x) + 2 \pi cos(\pi x) sin(\pi y) + (x+y) sin(\pi x) sin(\pi y) - \\ +2 \pi^2 (x+y) sin(\pi x) sin(\pi y),\end{split}\]
+

For this problem, the parameters are

+
+\[\epsilon = 1, +k = 1\]
+

The exact solution is given by

+
+\[u(x,y) = (x + y) sin(\pi x) sin(\pi y)\]
+

We begin by introducing the various files required to run this example

+
+

Contents

+ +

The code in this example can be run using

+
python3 main_helmholtz_hard.py input.yaml
+
+
+
+
+

Example File

+

The example file, helmholtz_example.py, defines the boundary +conditions and boundary values, the forcing function and exact function +(if test error needs to be calculated), bilinear parameters and the +actual value of the parameter that needs to be estimated (if the error +between the actual and estimated parameter needs to be calculated)

+
+

Defining boundary values

+

Boundary values are defined using the functions get_boundary_function_dict and get_bound_cond_dict.

+
+Unit Square +
+

For internally generated geometries, the boundary id’s will be hardcoded to +1000 for bottom, 1001 for right, 1002 for top, and 1003 for left; as shown in figure.

+
+
+

Defining the forcing function

+

rhs can be used to define the forcing function \(f\).

+
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
+
+
+
+
+

Defining bilinear parameters

+

The bilinear parameters like diffusion constant can be defined by +get_bilinear_params_dict

+
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}
+
+
+

Here, eps denoted the diffusion constant.

+

Back to Contents

+
+
+
+

Input file

+

The input file, input.yaml, is used to define inputs to your solver. +These will usually parameters that will changed often throughout your +experimentation, hence it is best practice to pass these parameters +externally. The input file is divided based on the modules which use the +parameter in question, as follows - #``experimentation`` This +contains output_path, a string which specifies which folder will be +used to store your outputs.

+
+

geometry

+

This section defines the geometrical parameters for your domain. 1. In +this example, we set the mesh_generation_method as "internal". +This generates a regular quadrilateral domain with a uniform mesh. 2. +The parameters in internal_mesh_params define the x and y limits of +the quadrilateral domain(xmin, xmax, ymin and ymax), +number of cells in the domain in the x and y direction (n_cells_x +and n_cells_y), number of total boundary points +(n_boundary_points) and number of test points in x and y direction +(n_test_points_x and n_test_points_y). 3. mesh_type : +FastVPINNs currently provides support for quadrilateral elements only. +4. external_mesh_params can be used to specify parameters for the +external mesh, and can be ignored for this example

+
+
+

fe

+

The parameters related to the finite element space are defined here. 1. +fe_order sets the order of the finite element test functions. 2. +fe_type set which type of polynomial will be used as the finite +element test function. 3. quad_order is the number of quadrature in +each direction in each cell. Thus the total number of quadrature points +in each cell will be quad_order\(^2\) 4. quad_type +specifies the quadrature rule to be used.

+
+
+

pde

+

beta specifies the weight by which the boundary loss will be +multiplied before being added to the PDE loss.

+
+
+

model

+

The parameters pertaining to the neural network are specified here. 1. +model_architecture is used to specify the dimensions of the neural +network. In this example, [2, 30, 30, 30, 1] corresponds to a neural +network with 2 inputs (for a 2-dimensional problem), 1 output (for a +scalar problem) and 3 hidden layers with 30 neurons each. 2. +activation specifies the activation function to be used. 3. +use_attention specifies if attention layers are to be used in the +model. This feature is currently under development and hence should be +set to false for now. 4. epochs is the number of iterations for +which the network must be trained. 5. dtype specifies which datatype +(float32 or float64) will be used for the tensor calculations. +6. set_memory_growth, when set to True will enable tensorflow’s +memory growth function, restricting the memory usage on the GPU. This is +currently under development and must be set to False for now. 7. +learning_rate sets the learning rate initial_learning_rate if a +constant learning rate is used. A learning rate scheduler can be used by +toggling use_lr_scheduler to True and setting the corresponding +decay parameters below it.

+
+
+

logging

+

It specifies the frequency with which the progress bar and console +output will be updated, and at what interval will inference be carried +out to print the solution image in the output folder.

+

Back to contents

+
+
+
+

Main file

+

This is the main file which needs to be run for the experiment, with the +input file as an argument. For the example, we will use the main file +main_helmholtz.py

+

Following are the key components of a FastVPINNs main file

+
+

Import relevant FastVPINNs methods

+
from fastvpinns.data.datahandler2d import DataHandler2D
+from fastvpinns.FE.fespace2d import Fespace2D
+from fastvpinns.Geometry.geometry_2d import Geometry_2D
+
+
+

Will import the functions related to setting up the finite element +space, 2D Geometry and the datahandler required to manage data and make +it available to the model.

+
from fastvpinns.model.modelimport DenseModel
+
+
+

Will import the model file where the neural network and its training +function is defined. The model file model.py contains the +DenseModel class. the train_step function of this model is used +to train the model.

+
from fastvpinns.physics.poisson2d import pde_loss_helmholtz
+
+
+

Imports the loss function for the 2-dimensional Poisson problem.

+
from fastvpinns.utils.compute_utils import compute_errors_combined
+from fastvpinns.utils.plot_utils import plot_contour, plot_loss_function, plot_test_loss_function
+from fastvpinns.utils.print_utils import print_table
+
+
+

Imports functions to calculate the loss, plot the results and print +outputs to the console.

+
+
+

Reading the Input File

+

The input file is loaded into config and the input parameters are +read and assigned to their respective variables.

+
+
+

Setting up 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)
+
+
+

will instantiate a Geometry_2D object, domain, with the mesh +type, mesh generation method and test points. In our example, the mesh +generation method is internal, so the cells and boundary points will +be obtained using the generate_quad_mesh_internal method.

+
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,
+)
+
+
+

Back to contents

+
+
+

Reading the boundary conditions and values

+

As explained in the example file section, the +boundary conditions and values are read as a dictionary from the example +file

+
bound_function_dict, bound_condition_dict = get_boundary_function_dict(), get_bound_cond_dict()
+
+
+
+
+

Setting up the finite element space

+
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,
+)
+
+
+

fespace will contain all the information about the finite element +space, including those read from the input file

+

Back to contents

+
+
+

Instantiating a model

+
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,
+)
+
+
+

In this problem, we pass the loss function pde_loss_helmholtz from +the physics file helmholtz2d.

+

We are now ready to train the model to approximate the solution of the +PDE.

+
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)
+        ...
+
+
+

Back to contents

+
+
+
+

Solution

+
+Exact Solution +
+

Exact Solution

+
+
+
+Predicted Solution +
+

Predicted Solution

+
+
+
+Error +
+

Error

+
+
+

Back to contents

+
+
+

References

+
    +
  1. FastVPINNs: Tensor-Driven Acceleration of VPINNs for Complex +Geometries.

  2. +
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_rst/tutorials/forward_problems_2d/uniform_mesh/poisson_2d/poisson2d_uniform.html b/_rst/tutorials/forward_problems_2d/uniform_mesh/poisson_2d/poisson2d_uniform.html new file mode 100644 index 0000000..49eeec3 --- /dev/null +++ b/_rst/tutorials/forward_problems_2d/uniform_mesh/poisson_2d/poisson2d_uniform.html @@ -0,0 +1,460 @@ + + + + + + + Solving forward problems with FastVPINNs : Poisson - 2D — fastvpinns 1.0.0 documentation + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Solving forward problems with FastVPINNs : Poisson - 2D

+

In this example, we will learn how to solve a 2-dimensional Poisson problem using FastVPINNs. +All the necessary files can be found in the examples folder of the fastvpinns GitHub repository

+
+\[-\epsilon\Delta u(x) = f(x), \quad \ x \in \Omega = (-1, 1)^2\]
+

where

+
+\[f(x,y) = -2\omega^2\sin{\omega x}\sin{\omega y}\]
+

For an \(\epsilon = 1\), and considering \(\omega = 2 \pi\) the +exact solution is given by

+
+\[u(x,y) = -\sin{2 \pi x}\sin{2 \pi y}\]
+

We begin by introducing the various files required to run this example

+
+

Contents

+ +

The code in this example can be run using

+
python3 main_poisson2d_hard.py input.yaml
+
+
+
+
+

Example File

+

The example file, sin_cos.py, defines the boundary conditions and +boundary values, the forcing function and exact function (if test error +needs to be calculated), bilinear parameters and the actual value of the +parameter that needs to be estimated (if the error between the actual +and estimated parameter needs to be calculated)

+
+

Defining boundary values

+

Boundary values are defined using the functions get_boundary_function_dict and get_bound_cond_dict.

+
+Unit Square +
+

For internally generated geometries, the boundary id’s will be hardcoded to +1000 for bottom, 1001 for right, 1002 for top, and 1003 for left; as shown in figure.

+
+
+

Defining the forcing function

+

rhs can be used to define the forcing function \(f\).

+
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
+
+
+
+
+

Defining bilinear parameters

+

The bilinear parameters like diffusion constant can be defined by +get_bilinear_params_dict

+
def get_bilinear_params_dict():
+    """
+    This function will return a dictionary of bilinear parameters
+    """
+    eps = 1.0
+
+    return {"eps": eps}
+
+
+

Here, eps denoted the diffusion constant.

+

Back to Contents

+
+
+
+

Input file

+

The input file, input.yaml, is used to define inputs to your solver. +These will usually parameters that will changed often throughout your +experimentation, hence it is best practice to pass these parameters +externally. The input file is divided based on the modules which use the +parameter in question, as follows - experimentation This +contains output_path, a string which specifies which folder will be +used to store your outputs.

+
+

geometry

+

This section defines the geometrical parameters for your domain. 1. In +this example, we set the mesh_generation_method as "internal". +This generates a regular quadrilateral domain with a uniform mesh. 2. +The parameters in internal_mesh_params define the x and y limits of +the quadrilateral domain(xmin, xmax, ymin and ymax), +number of cells in the domain in the x and y direction (n_cells_x +and n_cells_y), number of total boundary points +(n_boundary_points) and number of test points in x and y direction +(n_test_points_x and n_test_points_y). 3. mesh_type : +FastVPINNs currently provides support for quadrilateral elements only. +4. external_mesh_params can be used to specify parameters for the +external mesh, and can be ignored for this example

+
+
+

fe

+

The parameters related to the finite element space are defined here. 1. +fe_order sets the order of the finite element test functions. 2. +fe_type set which type of polynomial will be used as the finite +element test function. 3. quad_order is the number of quadrature in +each direction in each cell. Thus the total number of quadrature points +in each cell will be quad_order\(^2\) 4. quad_type +specifies the quadrature rule to be used.

+
+
+

pde

+

beta specifies the weight by which the boundary loss will be +multiplied before being added to the PDE loss.

+
+
+

model

+

The parameters pertaining to the neural network are specified here. 1. +model_architecture is used to specify the dimensions of the neural +network. In this example, [2, 30, 30, 30, 1] corresponds to a neural +network with 2 inputs (for a 2-dimensional problem), 1 output (for a +scalar problem) and 3 hidden layers with 30 neurons each. 2. +activation specifies the activation function to be used. 3. +use_attention specifies if attention layers are to be used in the +model. This feature is currently under development and hence should be +set to false for now. 4. epochs is the number of iterations for +which the network must be trained. 5. dtype specifies which datatype +(float32 or float64) will be used for the tensor calculations. +6. set_memory_growth, when set to True will enable tensorflow’s +memory growth function, restricting the memory usage on the GPU. This is +currently under development and must be set to False for now. 7. +learning_rate sets the learning rate initial_learning_rate if a +constant learning rate is used. A learning rate scheduler can be used by +toggling use_lr_scheduler to True and setting the corresponding +decay parameters below it.

+
+
+

logging

+

It specifies the frequency with which the progress bar and console +output will be updated, and at what interval will inference be carried +out to print the solution image in the output folder.

+

Back to contents

+
+
+
+

Main file

+

This is the main file which needs to be run for the experiment, with the +input file as an argument. For the example, we will use the main file +main_poisson2d.py

+

Following are the key components of a FastVPINNs main file

+
+

Import relevant FastVPINNs methods

+
from fastvpinns.data.datahandler2d import DataHandler2D
+from fastvpinns.FE.fespace2d import Fespace2D
+from fastvpinns.Geometry.geometry_2d import Geometry_2D
+
+
+

Will import the functions related to setting up the finite element +space, 2D Geometry and the datahandler required to manage data and make +it available to the model.

+
from fastvpinns.model.modelimport DenseModel
+
+
+

Will import the model file where the neural network and its training +function is defined. The model file model.py contains the +DenseModel class. the train_step function of this model is used +to train the model.

+
from fastvpinns.physics.poisson2d import pde_loss_poisson
+
+
+

Imports the loss function for the 2-dimensional Poisson problem.

+
from fastvpinns.utils.compute_utils import compute_errors_combined
+from fastvpinns.utils.plot_utils import plot_contour, plot_loss_function, plot_test_loss_function
+from fastvpinns.utils.print_utils import print_table
+
+
+

Imports functions to calculate the loss, plot the results and print +outputs to the console.

+
+
+

Reading the Input File

+

The input file is loaded into config and the input parameters are +read and assigned to their respective variables.

+
+
+

Setting up 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)
+
+
+

will instantiate a Geometry_2D object, domain, with the mesh +type, mesh generation method and test points. In our example, the mesh +generation method is internal, so the cells and boundary points will +be obtained using the generate_quad_mesh_internal method.

+
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,
+)
+
+
+

Back to contents

+
+
+

Reading the boundary conditions and values

+

As explained in the example file section, the +boundary conditions and values are read as a dictionary from the example +file

+
bound_function_dict, bound_condition_dict = get_boundary_function_dict(), get_bound_cond_dict()
+
+
+
+
+

Setting up the finite element space

+
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,
+)
+
+
+

fespace will contain all the information about the finite element +space, including those read from the input file

+

Back to contents

+
+
+

Instantiating a model

+
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,
+)
+
+
+

In this problem, we pass the loss function pde_loss_poisson from the +physics file poisson2d.py.

+

We are now ready to train the model to approximate the solution of the +PDE.

+
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)
+        ...
+
+
+

Back to contents

+
+
+
+

Solution

+Exact Solution +Predicted Solution +Error +

Back to contents

+
+
+

References

+
    +
  1. FastVPINNs: Tensor-Driven Acceleration of VPINNs for Complex +Geometries.

  2. +
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_rst/tutorials/inverse_problems_2d/const_inverse_poisson2d/inverse_constant.html b/_rst/tutorials/inverse_problems_2d/const_inverse_poisson2d/inverse_constant.html new file mode 100644 index 0000000..b4444da --- /dev/null +++ b/_rst/tutorials/inverse_problems_2d/const_inverse_poisson2d/inverse_constant.html @@ -0,0 +1,548 @@ + + + + + + + Solving Inverse Problems with FastVPINNs : Estimation of uniform diffusion parameter on a quadrilateral geometry. — fastvpinns 1.0.0 documentation + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Solving Inverse Problems with FastVPINNs : Estimation of uniform diffusion parameter on a quadrilateral geometry.

+

In this example, we will learn how to solve inverse problems using +FastVPINNs. In particular, we will solve the 2-dimensional Poisson +equation, as shown below, while simultaneously estimating the uniform +diffusion parameter \(\epsilon\) using synthetically generated +sensor data.

+
+\[-\epsilon\Delta u(x) = f(x), \quad \ x \in \Omega = (-1, 1)^2\]
+

for the actual solution +\(u(x, y) = 10 \sin(x) \tanh(x) e^{-\epsilon x^2}\) In this problem, +the actual value of the diffusion parameter, +\(\epsilon_{\text{actual}}\) is 0.3, and we start with an initial +guess of \(\epsilon_{\text{initial}}=2.0\).

+

We begin by introducing the various files required to run this example

+
+

Contents

+ +

The code in this example can be run using

+
python3 main_inverse.py input_inverse.yaml
+
+
+
+
+

Example File

+

The example file, inverse_uniform.py, defines the boundary +conditions and boundary values, the forcing function and exact function +(if test error needs to be calculated), bilinear parameters and the +actual value of the parameter that needs to be estimated (if the error +between the actual and estimated parameter needs to be calculated) ### +Defining boundary values The current version of FastVPINNs only +implements Dirichlet boundary conditions. The boundary values can be set +by defining a function for each boundary,

+
EPS = 0.3
+
+
+def left_boundary(x, y):
+    """
+    This function will return the boundary value for given component of a boundary
+    """
+    val = np.sin(x) * np.tanh(x) * np.exp(-1.0 * EPS * (x**2)) * 10
+    return val
+
+
+

Here EPS is the actual value of the diffusion parameter to be +estimated. In the above snippet, we define a function left_boundary +which returns the Dirichlet values to be enforced at that boundary. +Similarly, we can define more boundary functions like +right_boundary, top_boundary and bottom_boundary. Once these +functions are defined, we can assign them to the respective boundaries +using get_boundary_function_dict

+
+Unit Square +
+
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}
+
+
+

Here, 1000, 1001, etc. are the boundary identifiers obtained +from the geometry. Thus, each boundary gets mapped to it boundary value +in the dictionary.

+
+

Defining boundary conditions

+

As explained above, each boundary has an identifier. The function +get_bound_cond_dict maps the boundary identifier to the boundary +condition (only Dirichlet boundary condition is implemented at this +point).

+
def get_bound_cond_dict():
+    """
+    This function will return a dictionary of boundary conditions
+    """
+    return {1000: "dirichlet", 1001: "dirichlet", 1002: "dirichlet", 1003: "dirichlet"}
+
+
+
+
+

Defining the forcing function

+

rhs can be used to define the forcing function \(f\).

+
def rhs(x, y):
+    """
+    This function will return the value of the rhs at a given point
+    """
+
+    X = x
+    Y = y
+    eps = EPS
+
+    return (
+        -EPS
+        * (
+            40.0 * X * eps * (np.tanh(X) ** 2 - 1) * np.sin(X)
+            - 40.0 * X * eps * np.cos(X) * np.tanh(X)
+            + 10 * eps * (4.0 * X**2 * eps - 2.0) * np.sin(X) * np.tanh(X)
+            + 20 * (np.tanh(X) ** 2 - 1) * np.sin(X) * np.tanh(X)
+            - 20 * (np.tanh(X) ** 2 - 1) * np.cos(X)
+            - 10 * np.sin(X) * np.tanh(X)
+        )
+        * np.exp(-1.0 * X**2 * eps)
+    )
+
+
+
+
+

Defining bilinear parameters

+

The bilinear parameters like diffusion constant and convective velocity +can be defined by get_bilinear_params_dict

+
def get_bilinear_params_dict():
+    """
+    This function will return a dictionary of bilinear parameters
+    """
+    # Initial Guess
+    eps = EPS
+
+    return {"eps": eps}
+
+
+

Here, eps denoted the diffusion constant.

+
+
+

Defining the target parameter values for testing

+

To test if our solver converges to the correct value of the parameter to +be estimated, we use the function get_inverse_params_actual_dict.

+
def get_inverse_params_actual_dict():
+    """
+    This function will return a dictionary of inverse parameters
+    """
+    # Initial Guess
+    eps = EPS
+
+    return {"eps": eps}
+
+
+

This can then be used to calculate some error metric that assesses the +performance of our solver.

+

Back to Contents

+
+
+
+

Input file

+

The input file, input_inverse.yaml, is used to define inputs to your +solver. These will usually parameters that will changed often throughout +your experimentation, hence it is best practice to pass these parameters +externally. The input file is divided based on the modules which use the +parameter in question, as follows - ### experimentation This +contains output_path, a string which specifies which folder will be +used to store your outputs.

+
+

geometry

+

This section defines the geometrical parameters for your domain. 1. In +this example, we set the mesh_generation_method as "internal". +This generates a regular quadrilateral domain with a uniform mesh. 2. +The parameters in internal_mesh_params define the x and y limits of +the quadrilateral domain(xmin, xmax, ymin and ymax), +number of cells in the domain in the x and y direction (n_cells_x +and n_cells_y), number of total boundary points +(n_boundary_points) and number of test points in x and y direction +(n_test_points_x and n_test_points_y). 3. mesh_type : +FastVPINNs currently provides support for quadrilateral elements only. +4. external_mesh_params can be used to specify parameters for the +external mesh, and can be ignored for this example

+
+
+

fe

+

The parameters related to the finite element space are defined here. +1. fe_order sets the order of the finite element test functions.

+

2. fe_type set which type of polynomial will be used as the finite +element test function.

+

3. quad_order is the number of quadrature in +each direction in each cell. Thus the total number of quadrature points +in each cell will be quad_order\(^2\)

+
    +
  1. quad_type specifies the quadrature rule to be used.

  2. +
+
+
+

pde

+

beta specifies the weight by which the boundary loss will be +multiplied before being added to the PDE loss.

+
+
+

model

+

The parameters pertaining to the neural network are specified here. 1. +model_architecture is used to specify the dimensions of the neural +network. In this example, [2, 30, 30, 30, 1] corresponds to a neural +network with 2 inputs (for a 2-dimensional problem), 1 output (for a +scalar problem) and 3 hidden layers with 30 neurons each. 2. +activation specifies the activation function to be used. 3. +use_attention specifies if attnention layers are to be used in the +model. This feature is currently under development and hence should be +set to false for now. 4. epochs is the number of iterations for +which the network must be trained. 5. dtype specifies which datatype +(float32 or float64) will be used for the tensor calculations. +6. set_memory_growth, when set to True will enable tensorflow’s +memory growth function, restricting the memory usage on the GPU. This is +currently under development and must be set to False for now. 7. +learning_rate sets the learning rate initial_learning_rate if a +constant learning rate is used. A learning rate scheduler can be used by +toggling use_lr_scheduler to True and setting the corresponding +decay parameters below it.

+
+
+

logging

+

It specifies the frequency with which the progress bar and console +output will be updated, and at what interval will inference be carried +out to print the solution image in the output folder.

+
+
+

inverse

+

Specific inputs only for inverse problems. num_sensor_points +specifies the number of points in the domain at which the solution is +known (or “sensed”).

+

Back to contents

+
+
+
+

Main file

+

This is the main file which needs to be run for the experiment, with the +input file as an argument. For the example, we will use the main file +main_inverse.py

+

Following are the key components of a FastVPINNs main file

+
+

Import relevant FastVPINNs methods

+
from fastvpinns.data.datahandler2d import DataHandler2D
+from fastvpinns.FE.fespace2d import Fespace2D
+from fastvpinns.Geometry.geometry_2d import Geometry_2D
+
+
+

Will import the functions related to setting up the finite element +space, 2D Geometry and the datahandler required to manage data and make +it available to the model.

+
from fastvpinns.model.model_inverse import DenseModel_Inverse
+
+
+

Will import the model file where the neural network and its training +function is defined. The model file model_inverse.py contains the +DenseModel_Inverse class specifically designed for inverse problems +where a spatially varying parameter has to be estimated along with the +solution.

+
from fastvpinns.physics.poisson2d_inverse import *
+
+
+

Imports the loss function specifically designed for this problem, with a +sensor loss added to the PDE and boundary losses.

+
from fastvpinns.utils.compute_utils import compute_errors_combined
+from fastvpinns.utils.plot_utils import plot_contour, plot_loss_function, plot_test_loss_function
+from fastvpinns.utils.print_utils import print_table
+
+
+

Imports functions to calculate the loss, plot the results and print +outputs to the console.

+
+
+

Reading the Input File

+

The input file is loaded into config and the input parameters are +read and assigned to their respective variables.

+
+
+

Setting up 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)
+
+
+

will instantiate a Geometry_2D object, domain, with the mesh +type, mesh generation method and test points. In our example, the mesh +generation method is internal, so the cells and boundary points will +be obtained using the generate_quad_mesh_internal method.

+
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,
+)
+
+
+
+
+

Reading the boundary conditions and values

+

As explained in the example file section, the +boundary conditions and values are read as a dictionary from the example +file

+
bound_function_dict, bound_condition_dict = get_boundary_function_dict(), get_bound_cond_dict()
+
+
+
+
+

Setting up the finite element space

+
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,
+)
+
+
+

fespace will contain all the information about the finite element +space, including those read from the input file

+
+
+

Instantiating an inverse problem model

+
model = DenseModel_Inverse(
+    layer_dims=i_model_architecture,
+    learning_rate_dict=i_learning_rate_dict,
+    params_dict=params_dict,
+    loss_function=pde_loss_poisson_inverse,
+    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,
+    sensor_list=[points, sensor_values],
+    inverse_params_dict=inverse_params_dict,
+    tensor_dtype=i_dtype,
+    use_attention=i_use_attention,
+    activation=i_activation,
+    hessian=False,
+)
+
+
+

DenseModel_Inverse is a model written for inverse problems with +spatially varying parameter estimation. In this problem, we pass the +loss function pde_loss_poisson_inverse from the physics file +poisson_inverse.py.

+

We are now ready to train the model to approximate the solution of the +PDE while estimating the unknown diffusion parameter using the sensor +data.

+
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)
+        ...
+
+
+

Back to contents

+
+
+
+

Solution

+
+
+Exact Solution +
+

Exact Solution

+
+
+
+Predicted Solution +
+

Predicted Solution

+
+
+
+Error +
+

Error

+
+
+
+inverse_eps_prediction +
+

inverse_eps_prediction

+
+
+
+Train Loss +
+

Train Loss

+
+
+
+
+
+

References

+
    +
  1. FastVPINNs: Tensor-Driven Acceleration of VPINNs for Complex +Geometries.

  2. +
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_rst/tutorials/inverse_problems_2d/domain_inverse_cd2d/domain_inverse.html b/_rst/tutorials/inverse_problems_2d/domain_inverse_cd2d/domain_inverse.html new file mode 100644 index 0000000..76af1c9 --- /dev/null +++ b/_rst/tutorials/inverse_problems_2d/domain_inverse_cd2d/domain_inverse.html @@ -0,0 +1,536 @@ + + + + + + + Solving Inverse Problems with FastVPINNs : Estimation of spatially varying parameter on a complex geometry. — fastvpinns 1.0.0 documentation + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Solving Inverse Problems with FastVPINNs : Estimation of spatially varying parameter on a complex geometry.

+

In this example, we will learn how to solve inverse problems on a +complex geometry using FastVPINNs. In particular, we will solve the +2-dimensional convection-diffusion equation, as shown below, while +simultaneously estimating the spatially dependent diffusion parameter +\(\epsilon(x,y)\) using synthetically generated sensor data.

+
+\[-\left(\frac{\partial}{\partial x}\left(\epsilon(x,y)\frac{\partial u}{\partial x}\right) + \frac{\partial}{\partial y}\left(\epsilon(x,y)\frac{\partial u}{\partial y}\right)\right) + b_x\frac{\partial u}{\partial x} + b_y\frac{\partial u}{\partial y} = f\]
+

where

+
+\[f=10; \quad \epsilon_{\text{actual}}=0.5\times(\sin{x} + \cos{y}); \qquad b_x=1.0; \quad b_y=0.0\]
+

We begin by introducing the various files required to run this example

+
+

Computational Domain

+

The computational domain is a circular domain with radius 1 centered at +(0, 0).

+
+alt text +
+
+

Contents

+
    +
  • Example File: The boundary conditions, forcing +function \(f\) and parameters are defined in this file.

  • +
  • Input File: The input file contains parameters for +the finite element space and neural networks that can be tuned.

  • +
  • Main File: The main file is the file that is +actually run.

  • +
+

The code in this example can be run using

+
python3 main_inverse_domain_circle.py input_inverse_domain.yaml
+
+
+
+
+

Example File

+

The example file, cd2d_inverse_circle_example.py, defines the +boundary conditions and boundary values, the forcing function and exact +function (if test error needs to be calculated), bilinear parameters and +the actual value of the parameter that needs to be estimated (if the +error between the actual and estimated parameter needs to be calculated)

+
+
+

Defining boundary values

+

The current version of FastVPINNs only +implements Dirichlet boundary conditions. The boundary values can be set +by defining a function for each boundary,

+
def circle_boundary(x, y):
+    """
+    This function will return the boundary value for given component of a boundary
+    """
+    val = np.ones_like(x) * 0.0
+    return val
+
+
+

The function circle_boundary returns the boundary value for a given +component of the boundary. The function get_boundary_function_dict +returns a dictionary of boundary functions. The key of the dictionary is +the boundary id and the value is the boundary function. The function +get_bound_cond_dict returns a dictionary of boundary conditions. The +key of the dictionary is the boundary id and the value is the boundary +condition.

+
def get_boundary_function_dict():
+    """
+    This function will return a dictionary of boundary functions
+    """
+    return {1000: circle_boundary}
+
+
+

For externally created geometries from gmsh, the user needs to provide +the physical tag for the boundaries present in the geometry. +In our case, we have used 1000 to define the circular boundary in mesh file.

+
+Unit Circle +
+
+

Defining boundary conditions

+

As explained above, each boundary has an identifier. The function +get_bound_cond_dict maps the boundary identifier to the boundary +condition (only Dirichlet boundary condition is implemented at this +point).

+
def get_bound_cond_dict():
+    """
+    This function will return a dictionary of boundary conditions
+    """
+    return {1000: circle_boundary}
+
+
+
+
+

Defining the forcing function

+

rhs can be used to define the forcing function \(f\).

+
def rhs(x, y):
+    """
+    This function will return the value of the rhs at a given point
+    """
+    return 10.0 * np.ones_like(x)
+
+
+
+
+

Defining bilinear parameters

+

The bilinear parameters like diffusion constant and convective velocity +can be defined by get_bilinear_params_dict

+
def get_bilinear_params_dict():
+    """
+    This function will return a dictionary of bilinear parameters
+    """
+
+    eps = 0.1  # will not be used in the loss function, as it will be replaced by the predicted value of NN
+    b1 = 1
+    b2 = 0
+    c = 0.0
+
+    return {"eps": eps, "b_x": b1, "b_y": b2, "c": c}
+
+
+

Here, eps denoted the diffusion constant, b_x and b_y denote +the convective velocity in x and y direction respectively, and c +denotes the reaction term. In this particular example, eps is not +used in the loss calculation since it is the parameter to be estimated +and c is zero since this is simply a convection-diffusion problem.

+
+
+

Defining the target parameter values for testing

+

To test if our solver converges to the correct value of the parameter to +be estimated, we use the function get_inverse_params_actual_dict.

+
def get_inverse_params_actual_dict(x, y):
+    """
+    This function will return a dictionary of inverse parameters
+    """
+    # Initial Guess
+    eps = 0.5 * (np.sin(x) + np.cos(y))
+    return {"eps": eps}
+
+
+

This can then be used to calculate some error metric that assesses the +performance of our solver.

+

Back to Contents

+
+
+
+

Input file

+

The input file, input_inverse_domain.yaml, is used to define inputs +to your solver. These will usually parameters that will changed often +throughout your experimentation, hence it is best practice to pass these +parameters externally. The input file is divided based on the modules +which use the parameter in question, as follows - ### +experimentation This contains output_path, a string which +specifies which folder will be used to store your outputs.

+
+

geometry

+

This section defines the geometrical parameters for your domain. 1. In +this example, we set the mesh_generation_method as "external" +since we want to read the mesh file for the circular domain, +circular_quad.mesh. 2. For the purposes of this example, the +parameters in internal_mesh_params can be ignored as they are used +exclusively for internal meshes. 3. mesh_type : FastVPINNs currently +provides support for quadrilateral elements only. 4. +external_mesh_params can be used to specify parameters for the +external mesh. mesh_file_name takes a string (circular_quad_mesh +in this case). boundary_refinement_level controls how many times the +boundaries are refined and in effect decides the number of boundary +points sampled. This sampling can be set to uniform for uniform +sampling.

+
+
+

fe

+

The parameters related to the finite element space are defined here. 1. +fe_order sets the order of the finite element test functions. 2. +fe_type set which type of polynomial will be used as the finite +element test function. 3. quad_order is the number of quadrature in +each direction in each cell. Thus the total number of quadrature points +in each cell will be quad_order\(^2\) 4. quad_type +specifies the quadrature rule to be used.

+
+
+

pde

+

beta specifies the weight by which the boundary loss will be +multiplied before being added to the PDE loss.

+
+
+

model

+

The parameters pertaining to the neural network are specified here. 1. +model_architecture is used to specify the dimensions of the neural +network. In this example, [2, 30, 30, 30, 1] corresponds to a neural +network with 2 inputs (for a 2-dimensional problem), 1 output (for a +scalar problem) and 3 hidden layers with 30 neurons each. 2. +activation specifies the activation function to be used. 3. +use_attention specifies if attnention layers are to be used in the +model. This feature is currently under development and hence should be +set to false for now. 4. epochs is the number of iterations for +which the network must be trained. 5. dtype specifies which datatype +(float32 or float64) will be used for the tensor calculations. +6. set_memory_growth, when set to True will enable tensorflow’s +memory growth function, restricting the memory usage on the GPU. This is +currently under development and must be set to False for now. 7. +learning_rate sets the learning rate initial_learning_rate if a +constant learning rate is used. A learning rate scheduler can be used by +toggling use_lr_scheduler to True and setting the corresponding +decay parameters below it.

+
+
+

logging

+

It specifies the frequency with which the progress bar and console +output will be updated, and at what interval will inference be carried +out to print the solution image in the output folder.

+
+
+

inverse

+

Specific inputs only for inverse problems. num_sensor_points +specifies the number of points in the domain at which the solution is +known (or “sensed”). This sensor data can be synthetic or be read from a +file given by sensor_data_file.

+

Back to contents

+
+
+
+

Main file

+

This is the main file which needs to be run for the experiment, with the +input file as an argument. For the example, we will use the main file +main_inverse_domain_circle.py

+

Following are the key components of a FastVPINNs main file

+
+

Import relevant FastVPINNs methods

+
from fastvpinns.data.datahandler2d import DataHandler2D
+from fastvpinns.FE.fespace2d import Fespace2D
+from fastvpinns.Geometry.geometry_2d import Geometry_2D
+
+
+

Will import the functions related to setting up the finite element +space, 2D Geometry and the datahandler required to manage data and make +it available to the model.

+
from fastvpinns.model.model_inverse_domain import DenseModel_Inverse_Domain
+
+
+

Will import the model file where the neural network and its training +function is defined. The model file model_inverse_domain.py contains +the DenseModel_Inverse_Domain class specifically designed for +inverse problems where a spatially varying parameter has to be estimated +along with the solution.

+
from fastvpinns.physics.cd2d_inverse_domain import *
+
+
+

Imports the loss function specifically designed for this problem, with a +sensor loss added to the PDE and boundary losses.

+
from fastvpinns.utils.compute_utils import compute_errors_combined
+from fastvpinns.utils.plot_utils import plot_contour, plot_loss_function, plot_test_loss_function
+from fastvpinns.utils.print_utils import print_table
+
+
+

Imports functions to calculate the loss, plot the results and print +outputs to the console.

+
+
+

Reading the Input File

+

The input file is loaded into config and the input parameters are +read and assigned to their respective variables.

+
+
+

Setting up 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)
+
+
+

will instantiate a Geometry_2D object, domain, with the mesh +type, mesh generation method and test points. In our example, the mesh +generation method is external, so the cells and boundary points will +be obtained using the read_mesh method.

+
cells, boundary_points = domain.read_mesh(mesh_file=i_mesh_file_name, boundary_point_refinement_level=i_boundary_refinement_level,
+            bd_sampling_method=i_boundary_sampling_method,
+            refinement_level=0)
+
+
+
+
+

Reading the boundary conditions and values

+

As explained in the example file section, the +boundary conditions and values are read as a dictionary from the example +file

+
bound_function_dict, bound_condition_dict = get_boundary_function_dict(), get_bound_cond_dict()
+
+
+
+
+

Setting up the finite element space

+
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,
+)
+
+
+
+
fespace will contain all the information about the finite element +space, including those read from the input file
+
#Instantiating an inverse problem model
+
+
model = DenseModel_Inverse_Domain(
+    layer_dims=i_model_architecture,
+    learning_rate_dict=i_learning_rate_dict,
+    params_dict=params_dict,
+    loss_function=pde_loss_cd2d_inverse_domain,
+    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,
+    sensor_list=[points, sensor_values],
+    tensor_dtype=i_dtype,
+    use_attention=i_use_attention,
+    activation=i_activation,
+    hessian=False,
+)
+
+
+

DenseModel_Inverse_Domain is a model written for inverse problems +with spatially varying parameter estimation. In this problem, we pass +the loss function pde_loss_cd2d_inverse_domain from the physics +file cd2d_inverse_domain.py.

+

We are now ready to train the model to approximate the solution of the +PDE while estimating the unknown diffusion parameter using the sensor +data.

+
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)
+        ...
+
+
+
+
+
+

Solution

+
+Exact Solution +
+

Exact Solution

+
+
+
+Predicted Solution +
+

Predicted Solution

+
+
+
+Error +
+

Error

+
+
+
+Epsilon Exact +
+

Epsilon Exact

+
+
+
+Epsilon Predicted +
+

Epsilon Predicted

+
+
+
+Epsilon Error +
+

Epsilon Error

+
+
+

Back to contents

+
+
+

References

+
    +
  1. FastVPINNs: Tensor-Driven Acceleration of VPINNs for Complex +Geometries.

  2. +
+

Back to contents

+
+
+
+ + +
+
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/_sources/_rst/_cite.rst.txt b/_sources/_rst/_cite.rst.txt new file mode 100644 index 0000000..5ab6bb0 --- /dev/null +++ b/_sources/_rst/_cite.rst.txt @@ -0,0 +1,15 @@ +Cite FastVPINNs +=============== + +If you use fastvpinns for your research, please cite the following paper: + +.. code:: bibtex + + @misc{anandh2024fastvpinns, + title={FastVPINNs: Tensor-Driven Acceleration of VPINNs for Complex Geometries}, + author={Thivin Anandh and Divij Ghose and Himanshu Jain and Sashikumaar Ganesan}, + year={2024}, + eprint={2404.12063}, + archivePrefix={arXiv}, + primaryClass={cs.LG} + } \ No newline at end of file diff --git a/_sources/_rst/_contributing.rst.txt b/_sources/_rst/_contributing.rst.txt new file mode 100644 index 0000000..7b3e036 --- /dev/null +++ b/_sources/_rst/_contributing.rst.txt @@ -0,0 +1,18 @@ +How to Contribute +================= + +We welcome contributions to this project! Here are some guidelines to help you get started: + +1. **Open an Issue or Feature Request**: Before starting your work, please open an issue or feature request. This allows us to assign the task to you and avoid duplicate work. + +2. **Fork and Create a Branch**: Fork the repository and create a branch for your issue or feature. All changes should be made on this branch, not on the main branch. + +3. **Follow Coding Standards**: Please use proper indentation and linting. Install ``pre-commit`` and run it locally to format files using the ``black`` library and check the linting score. + +4. **Write Tests**: If you add new code, please also add corresponding test cases. Compute and update the test coverage by running ``build_release.py``. + +5. **Commit Messages**: Add a proper commit message that references the issue or feature request and includes well-documented comments. + +6. **Squash Commits**: Before raising a Pull Request (PR), squash your commits on the feature branch into a single commit. + +Thank you for contributing! \ No newline at end of file diff --git a/_sources/_rst/_installation.rst.txt b/_sources/_rst/_installation.rst.txt new file mode 100644 index 0000000..ebfacd1 --- /dev/null +++ b/_sources/_rst/_installation.rst.txt @@ -0,0 +1,55 @@ +Installation +============ + +The build of the code is currently tested on Python 3.8, 3.9, 3.10 and 3.11. The code is CI tested on environments provided by Github Actions such as `ubuntu-20.04`, `ubuntu-latest`, `macos-latest`, `windows-latest`, +refer to `Compatibility-CI `_ page for more details. + +Setting up an Virtual Environment +_________________________________ + +It is recommended to create a virtual environment to install the package. You can create a virtual environment using the following command: + +.. code-block:: bash + + python3 -m venv venv + source venv/bin/activate + +For conda users, you can create a virtual environment using the following command: + +.. code-block:: bash + + conda create -n fastvpinns python=3.8 + conda activate fastvpinns + + +Installing via PIP +__________________ + +You can simply install the package using pip as follows: + +.. code-block:: bash + + pip install fastvpinns + +On ubuntu/mac systems with libGL issues caused due to matplotlib or gmsh, please run the following command to install the required dependencies. + +.. code-block:: bash + + sudo apt-get install libgl1-mesa-glx + + +Installing from source +______________________ + +The official distribution is on GitHub, and you can clone the repository using + +.. code-block:: bash + + git clone https://github.com/cmgcds/fastvpinns.git + +To install the package just type: + +.. code-block:: bash + + cd fastvpinns + pip install -e . diff --git a/_sources/_rst/_licence.rst.txt b/_sources/_rst/_licence.rst.txt new file mode 100644 index 0000000..136ff27 --- /dev/null +++ b/_sources/_rst/_licence.rst.txt @@ -0,0 +1,24 @@ +License +======== + +MIT License + +Copyright (c) [2024] [Thivin Anandh, Divij Ghose, Sashikumaar Ganesan] + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/_sources/_rst/_team.rst.txt b/_sources/_rst/_team.rst.txt new file mode 100644 index 0000000..e3d675d --- /dev/null +++ b/_sources/_rst/_team.rst.txt @@ -0,0 +1,9 @@ +FastVPINNs Team +============== + +FastVPINNs is currently developed by `Thivin Anandh `_, `Divij Ghose `_, +under supervision of `Prof. Sashikumaar Ganesan `_ at `STARS LAB, Indian Institute of Science, Bangalore `_. + + +The Authors would like to acknowledge the support of Shell Technology Centre, India for their partial funding, We are thankful to the MHRD Grant No. STARS-1/388 (SPADE) +for partial support. \ No newline at end of file diff --git a/_sources/_rst/_tutorial.rst.txt b/_sources/_rst/_tutorial.rst.txt new file mode 100644 index 0000000..43f4c91 --- /dev/null +++ b/_sources/_rst/_tutorial.rst.txt @@ -0,0 +1,45 @@ +FastVPINNs Tutorials +==================== + +This page contains tutorials for solving 2D Partial Differential Equations (PDEs) using the FastVPINNs library. The tutorials are organized as follows: + +Forward Problems +------------------ +Problems on Uniform Mesh +~~~~~~~~~~~~~~~~~~~~~~~~ +.. toctree:: + :maxdepth: 1 + :titlesonly: + + Poisson Equation on unit square + Helmholtz Equation on unit square + +Problems on Complex geometry +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. toctree:: + :maxdepth: 1 + :titlesonly: + + Poisson Equation on unit circle + Helmholtz Equation on unit circle + Convection-Diffusion Equation on spur-gear geometry + Convection-Diffusion Equation on unit circle + + +Problems with Hard boundary constraints +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.. toctree:: + :maxdepth: 1 + :titlesonly: + + Poisson Equation with hard boundary constraints on unit square + +Inverse Problems +---------------- +.. toctree:: + :maxdepth: 1 + :titlesonly: + + Inverse problems with constant inverse parameter + Inverse problems with spatially varying inverse parameter diff --git a/_sources/_rst/fastvpinns.rst.txt b/_sources/_rst/fastvpinns.rst.txt new file mode 100644 index 0000000..a877e1a --- /dev/null +++ b/_sources/_rst/fastvpinns.rst.txt @@ -0,0 +1,201 @@ +FastVPINNs Module Documentation +=============================== + +This section covers the documentation of the FastVPINNs modules. The package is divided into several subpackages, each of which is documented in its own section. The main module documentation is provided below. + +- :ref:`FE ` - Finite Element routines for 2D domains +- :ref:`Geometry ` - Meshing and Geometry routines +- :ref:`Model ` - Dense Neural Network Model +- :ref:`Physics ` - Physics classes for the problem +- :ref:`Data ` - Data handling routines +- :ref:`Utils ` - Utility functions + + +.. _FE: + +FE +----------- + +---- + +This section holds the documentation for the FE module of the FastVPINNs package. The module provides the necessary classes and functions to obtain the finite element test functions and quadrature points for the 2D domain within the FastVPINNs package. This section is broadly classified into + +.. toctree:: + :maxdepth: 2 + :titlesonly: + +Finite Element Test Functions +'''''''''''''''''''''''''''''' + +.. toctree:: + :maxdepth: 2 + :titlesonly: + + Jacobi test functions + Basis function 2d(Abstract) + +.. toctree:: + :maxdepth: 2 + :titlesonly: + +Quadrature Functions +'''''''''''''''''''''''''''''' + +.. toctree:: + :maxdepth: 2 + :titlesonly: + + Quadrature Functions(Abstract) + Quadrature Functions-2D + +.. toctree:: + :maxdepth: 2 + :titlesonly: + +Finite Element Transformations +'''''''''''''''''''''''''''''' + +.. toctree:: + :maxdepth: 2 + :titlesonly: + + FE Transformation(Abstract) + Affine Transformations + Bilinear Transformations + + +.. toctree:: + :maxdepth: 2 + :titlesonly: + +Finite Element Setup +'''''''''''''''''''''''''''''' + +.. toctree:: + :maxdepth: 2 + :titlesonly: + + Fespace2D + FE2DSetupMain + FE2DCell + + +.. _Geometry: + +Geometry +----------- + +---- + +This section holds the documentation for the the geometry module of the FastVPINNs package. The module provides the necessary classes and functions to obtain the geometry information either from the external mesh file or from the internal mesh generation routines. This supports the generation of VTK and GMSH files for visualization purposes. + +.. toctree:: + :maxdepth: 2 + :titlesonly: + + Geometry(Abstract) + Geometry2D + + +.. _Model: + +Model +----------- + +---- + +This section holds the documentation for the the Model module of the FastVPINNs package. The module provides the necessary classes and functions to train a Variational physics informed neural network (VPINN) model for the given physics problem. The model contains only the information about the neural network architecture and the training process. The physics information is provided by the user in the form of a physics class. The model class is responsible for training the neural network and providing the necessary prediction functions. + +.. toctree:: + :maxdepth: 2 + :titlesonly: + +Model Types +'''''''''''''''''''''''''''''' + +.. toctree:: + :maxdepth: 2 + :titlesonly: + + Dense Model - Forward Problem + Dense Model - Forward Problem with hard constraints + Dense Model - Inverse Problem Constant Coefficient + Dense Model - Inverse Problem Spatially Varying Coefficient + +.. _Physics: + +Physics +----------- + +---- + +This section holds the documentation for the the Physics module of the FastVPINNs package. The module provides the necessary classes and functions to define the physics of the problem. The physics class contains the information about the governing equations and their loss calculation in the variational form. + +.. toctree:: + :maxdepth: 2 + :titlesonly: + +Forward Problems +'''''''''''''''''''''''''''''' + +.. toctree:: + :maxdepth: 2 + :titlesonly: + + Convection-Diffusion 2D + Helmholtz 2D + Poisson 2D + +Inverse Problems (Constant Coefficient) +'''''''''''''''''''''''''''''''''''''''' + +.. toctree:: + :maxdepth: 2 + :titlesonly: + + Convection-Diffusion-2D - Inverse Problem with Constant Coefficient + Poission-2D - Inverse Problem with Constant Coefficient + +Inverse Problems (Spatially Varying Coefficient) +'''''''''''''''''''''''''''''''''''''''''''''''' + +.. toctree:: + :maxdepth: 2 + :titlesonly: + + Convection-Diffusion-2D - Inverse Problem with Spatially Varying Coefficient + + +.. _Data: + +Data +----------- + +---- + +This section holds the documentation for the the datahandler module of the FastVPINNs package. The module provides the necessary classes and functions to handle the data for the training of the VPINN model. The datahandler class is responsible for generating and assembling the tensors into required format for the training process. + +.. toctree:: + :maxdepth: 2 + :titlesonly: + + DataHandler - Abstract class for all datahandler routines + DataHandler2D - DataHandler routines for 2D + + +.. _Utils: + +Utils +----------- + +---- + +This section holds the documentation for all the helper functions, which are responsible for plotting and console outputs. + +.. toctree:: + :maxdepth: 2 + :titlesonly: + + Plotting utils + Printing utils + Compute utils diff --git a/_sources/_rst/library/data/datahandler.rst.txt b/_sources/_rst/library/data/datahandler.rst.txt new file mode 100644 index 0000000..3371525 --- /dev/null +++ b/_sources/_rst/library/data/datahandler.rst.txt @@ -0,0 +1,7 @@ +fastvpinns.data.datahandler module +---------------------------------- + +.. automodule:: fastvpinns.data.datahandler + :members: + :undoc-members: + :show-inheritance: \ No newline at end of file diff --git a/_sources/_rst/library/data/datahandler2d.rst.txt b/_sources/_rst/library/data/datahandler2d.rst.txt new file mode 100644 index 0000000..d53bab1 --- /dev/null +++ b/_sources/_rst/library/data/datahandler2d.rst.txt @@ -0,0 +1,7 @@ +fastvpinns.data.datahandler2d module +------------------------------------ + +.. automodule:: fastvpinns.data.datahandler2d + :members: + :undoc-members: + :show-inheritance: diff --git a/_sources/_rst/library/fe2d/fe2d_affine_transformation.rst.txt b/_sources/_rst/library/fe2d/fe2d_affine_transformation.rst.txt new file mode 100644 index 0000000..a2f9e89 --- /dev/null +++ b/_sources/_rst/library/fe2d/fe2d_affine_transformation.rst.txt @@ -0,0 +1,7 @@ +fastvpinns.FE.quad\_affine module +------------------------------------- + +.. automodule:: fastvpinns.FE.quad_affine + :members: + :undoc-members: + :show-inheritance: diff --git a/_sources/_rst/library/fe2d/fe2d_basis_function.rst.txt b/_sources/_rst/library/fe2d/fe2d_basis_function.rst.txt new file mode 100644 index 0000000..1da4dd0 --- /dev/null +++ b/_sources/_rst/library/fe2d/fe2d_basis_function.rst.txt @@ -0,0 +1,7 @@ +fastvpinns.FE.basis\_2d\_QN\_Jacobi module +---------------------------------------------- + +.. automodule:: fastvpinns.FE.basis_2d_QN_Jacobi + :members: + :undoc-members: + :show-inheritance: \ No newline at end of file diff --git a/_sources/_rst/library/fe2d/fe2d_bilinear_transformation.rst.txt b/_sources/_rst/library/fe2d/fe2d_bilinear_transformation.rst.txt new file mode 100644 index 0000000..7104dee --- /dev/null +++ b/_sources/_rst/library/fe2d/fe2d_bilinear_transformation.rst.txt @@ -0,0 +1,7 @@ +fastvpinns.FE.quad\_bilinear module +--------------------------------------- + +.. automodule:: fastvpinns.FE.quad_bilinear + :members: + :undoc-members: + :show-inheritance: \ No newline at end of file diff --git a/_sources/_rst/library/fe2d/fe2d_fe2d_cell.rst.txt b/_sources/_rst/library/fe2d/fe2d_fe2d_cell.rst.txt new file mode 100644 index 0000000..886183e --- /dev/null +++ b/_sources/_rst/library/fe2d/fe2d_fe2d_cell.rst.txt @@ -0,0 +1,8 @@ +fastvpinns.FE.FE2D\_Cell module +----------------------------------- + +.. automodule:: fastvpinns.FE.FE2D_Cell + :members: + :undoc-members: + :show-inheritance: + diff --git a/_sources/_rst/library/fe2d/fe2d_fe2d_setup.rst.txt b/_sources/_rst/library/fe2d/fe2d_fe2d_setup.rst.txt new file mode 100644 index 0000000..63fa039 --- /dev/null +++ b/_sources/_rst/library/fe2d/fe2d_fe2d_setup.rst.txt @@ -0,0 +1,7 @@ +fastvpinns.FE.fe2d\_setup\_main module +------------------------------------------ + +.. automodule:: fastvpinns.FE.fe2d_setup_main + :members: + :undoc-members: + :show-inheritance: diff --git a/_sources/_rst/library/fe2d/fe2d_fespace2d.rst.txt b/_sources/_rst/library/fe2d/fe2d_fespace2d.rst.txt new file mode 100644 index 0000000..515cf27 --- /dev/null +++ b/_sources/_rst/library/fe2d/fe2d_fespace2d.rst.txt @@ -0,0 +1,7 @@ +fastvpinns.FE.fespace2d module +---------------------------------- + +.. automodule:: fastvpinns.FE.fespace2d + :members: + :undoc-members: + :show-inheritance: diff --git a/_sources/_rst/library/fe2d/fe2d_jacobi.rst.txt b/_sources/_rst/library/fe2d/fe2d_jacobi.rst.txt new file mode 100644 index 0000000..eafcb34 --- /dev/null +++ b/_sources/_rst/library/fe2d/fe2d_jacobi.rst.txt @@ -0,0 +1,11 @@ +fastvpinns.FE.basis\_2d\_QN\_Jacobi module +------------------------------------------ + +.. automodule:: fastvpinns.FE.basis_2d_QN_Jacobi + :members: + :undoc-members: + :show-inheritance: + + + + diff --git a/_sources/_rst/library/fe2d/fe2d_quadratureformulas.rst.txt b/_sources/_rst/library/fe2d/fe2d_quadratureformulas.rst.txt new file mode 100644 index 0000000..06039b0 --- /dev/null +++ b/_sources/_rst/library/fe2d/fe2d_quadratureformulas.rst.txt @@ -0,0 +1,7 @@ +fastvpinns.FE.quadratureformulas module +--------------------------------------- + +.. automodule:: fastvpinns.FE.quadratureformulas + :members: + :undoc-members: + :show-inheritance: \ No newline at end of file diff --git a/_sources/_rst/library/fe2d/fe2d_quadratureformulas2d.rst.txt b/_sources/_rst/library/fe2d/fe2d_quadratureformulas2d.rst.txt new file mode 100644 index 0000000..0b0c7a1 --- /dev/null +++ b/_sources/_rst/library/fe2d/fe2d_quadratureformulas2d.rst.txt @@ -0,0 +1,8 @@ +fastvpinns.FE.quadratureformulas\_quad2d module +--------------------------------------------------- + +.. automodule:: fastvpinns.FE.quadratureformulas_quad2d + :members: + :undoc-members: + :show-inheritance: + diff --git a/_sources/_rst/library/fe2d/fe2d_transformation.rst.txt b/_sources/_rst/library/fe2d/fe2d_transformation.rst.txt new file mode 100644 index 0000000..9456087 --- /dev/null +++ b/_sources/_rst/library/fe2d/fe2d_transformation.rst.txt @@ -0,0 +1,7 @@ +fastvpinns.FE.fe\_transformation\_2d module +----------------------------------------------- + +.. automodule:: fastvpinns.FE.fe_transformation_2d + :members: + :undoc-members: + :show-inheritance: diff --git a/_sources/_rst/library/fe2d/fespace.rst.txt b/_sources/_rst/library/fe2d/fespace.rst.txt new file mode 100644 index 0000000..b003f68 --- /dev/null +++ b/_sources/_rst/library/fe2d/fespace.rst.txt @@ -0,0 +1,7 @@ +fastvpinns.FE.fespace module +---------------------------- + +.. automodule:: fastvpinns.FE.fespace + :members: + :undoc-members: + :show-inheritance: \ No newline at end of file diff --git a/_sources/_rst/library/geometry/geometry.rst.txt b/_sources/_rst/library/geometry/geometry.rst.txt new file mode 100644 index 0000000..6c52a5c --- /dev/null +++ b/_sources/_rst/library/geometry/geometry.rst.txt @@ -0,0 +1,7 @@ +fastvpinns.Geometry.geometry module +----------------------------------- + +.. automodule:: fastvpinns.Geometry.geometry + :members: + :undoc-members: + :show-inheritance: \ No newline at end of file diff --git a/_sources/_rst/library/geometry/geometry2d.rst.txt b/_sources/_rst/library/geometry/geometry2d.rst.txt new file mode 100644 index 0000000..de01f65 --- /dev/null +++ b/_sources/_rst/library/geometry/geometry2d.rst.txt @@ -0,0 +1,7 @@ +fastvpinns.Geometry.geometry\_2d module +--------------------------------------- + +.. automodule:: fastvpinns.Geometry.geometry_2d + :members: + :undoc-members: + :show-inheritance: \ No newline at end of file diff --git a/_sources/_rst/library/model/model.rst.txt b/_sources/_rst/library/model/model.rst.txt new file mode 100644 index 0000000..50dbeef --- /dev/null +++ b/_sources/_rst/library/model/model.rst.txt @@ -0,0 +1,7 @@ +fastvpinns.model.model module +----------------------------- + +.. automodule:: fastvpinns.model.model + :members: + :undoc-members: + :show-inheritance: diff --git a/_sources/_rst/library/model/model_hard.rst.txt b/_sources/_rst/library/model/model_hard.rst.txt new file mode 100644 index 0000000..9b7ccf6 --- /dev/null +++ b/_sources/_rst/library/model/model_hard.rst.txt @@ -0,0 +1,7 @@ +fastvpinns.model.model\_hard module +----------------------------------- + +.. automodule:: fastvpinns.model.model_hard + :members: + :undoc-members: + :show-inheritance: diff --git a/_sources/_rst/library/model/model_inverse.rst.txt b/_sources/_rst/library/model/model_inverse.rst.txt new file mode 100644 index 0000000..00b8ebf --- /dev/null +++ b/_sources/_rst/library/model/model_inverse.rst.txt @@ -0,0 +1,7 @@ +fastvpinns.model.model\_inverse module +-------------------------------------- + +.. automodule:: fastvpinns.model.model_inverse + :members: + :undoc-members: + :show-inheritance: diff --git a/_sources/_rst/library/model/model_inverse_domain.rst.txt b/_sources/_rst/library/model/model_inverse_domain.rst.txt new file mode 100644 index 0000000..72fd6c3 --- /dev/null +++ b/_sources/_rst/library/model/model_inverse_domain.rst.txt @@ -0,0 +1,7 @@ +fastvpinns.model.model\_inverse\_domain module +---------------------------------------------- + +.. automodule:: fastvpinns.model.model_inverse_domain + :members: + :undoc-members: + :show-inheritance: diff --git a/_sources/_rst/library/physics/cd2d.rst.txt b/_sources/_rst/library/physics/cd2d.rst.txt new file mode 100644 index 0000000..e346fc9 --- /dev/null +++ b/_sources/_rst/library/physics/cd2d.rst.txt @@ -0,0 +1,7 @@ +fastvpinns.physics.cd2d module +------------------------------ + +.. automodule:: fastvpinns.physics.cd2d + :members: + :undoc-members: + :show-inheritance: diff --git a/_sources/_rst/library/physics/cd2d_inverse.rst.txt b/_sources/_rst/library/physics/cd2d_inverse.rst.txt new file mode 100644 index 0000000..d0563ec --- /dev/null +++ b/_sources/_rst/library/physics/cd2d_inverse.rst.txt @@ -0,0 +1,7 @@ +fastvpinns.physics.cd2d\_inverse module +--------------------------------------- + +.. automodule:: fastvpinns.physics.cd2d_inverse + :members: + :undoc-members: + :show-inheritance: diff --git a/_sources/_rst/library/physics/cd2d_inverse_domain.rst.txt b/_sources/_rst/library/physics/cd2d_inverse_domain.rst.txt new file mode 100644 index 0000000..ac77df9 --- /dev/null +++ b/_sources/_rst/library/physics/cd2d_inverse_domain.rst.txt @@ -0,0 +1,7 @@ +fastvpinns.physics.cd2d\_inverse\_domain module +----------------------------------------------- + +.. automodule:: fastvpinns.physics.cd2d_inverse_domain + :members: + :undoc-members: + :show-inheritance: diff --git a/_sources/_rst/library/physics/helmholtz2d.rst.txt b/_sources/_rst/library/physics/helmholtz2d.rst.txt new file mode 100644 index 0000000..c7e5c87 --- /dev/null +++ b/_sources/_rst/library/physics/helmholtz2d.rst.txt @@ -0,0 +1,7 @@ +fastvpinns.physics.helmholtz2d module +------------------------------------- + +.. automodule:: fastvpinns.physics.helmholtz2d + :members: + :undoc-members: + :show-inheritance: diff --git a/_sources/_rst/library/physics/poisson2d.rst.txt b/_sources/_rst/library/physics/poisson2d.rst.txt new file mode 100644 index 0000000..3b83ea1 --- /dev/null +++ b/_sources/_rst/library/physics/poisson2d.rst.txt @@ -0,0 +1,8 @@ +fastvpinns.physics.poisson2d module +----------------------------------- + +.. automodule:: fastvpinns.physics.poisson2d + :members: + :undoc-members: + :show-inheritance: + diff --git a/_sources/_rst/library/physics/poisson2d_inverse.rst.txt b/_sources/_rst/library/physics/poisson2d_inverse.rst.txt new file mode 100644 index 0000000..2d0c2af --- /dev/null +++ b/_sources/_rst/library/physics/poisson2d_inverse.rst.txt @@ -0,0 +1,8 @@ +fastvpinns.physics.poisson2d\_inverse module +-------------------------------------------- + +.. automodule:: fastvpinns.physics.poisson2d_inverse + :members: + :undoc-members: + :show-inheritance: + diff --git a/_sources/_rst/library/utils/compute_utils.rst.txt b/_sources/_rst/library/utils/compute_utils.rst.txt new file mode 100644 index 0000000..ce26db4 --- /dev/null +++ b/_sources/_rst/library/utils/compute_utils.rst.txt @@ -0,0 +1,7 @@ +fastvpinns.utils.compute\_utils module +-------------------------------------- + +.. automodule:: fastvpinns.utils.compute_utils + :members: + :undoc-members: + :show-inheritance: diff --git a/_sources/_rst/library/utils/plot_utils.rst.txt b/_sources/_rst/library/utils/plot_utils.rst.txt new file mode 100644 index 0000000..b5c49e7 --- /dev/null +++ b/_sources/_rst/library/utils/plot_utils.rst.txt @@ -0,0 +1,7 @@ +fastvpinns.utils.plot\_utils module +----------------------------------- + +.. automodule:: fastvpinns.utils.plot_utils + :members: + :undoc-members: + :show-inheritance: diff --git a/_sources/_rst/library/utils/print_utils.rst.txt b/_sources/_rst/library/utils/print_utils.rst.txt new file mode 100644 index 0000000..80a43a9 --- /dev/null +++ b/_sources/_rst/library/utils/print_utils.rst.txt @@ -0,0 +1,7 @@ +fastvpinns.utils.print\_utils module +------------------------------------ + +.. automodule:: fastvpinns.utils.print_utils + :members: + :undoc-members: + :show-inheritance: \ No newline at end of file diff --git a/_sources/_rst/modules.rst.txt b/_sources/_rst/modules.rst.txt new file mode 100644 index 0000000..64b0169 --- /dev/null +++ b/_sources/_rst/modules.rst.txt @@ -0,0 +1,7 @@ +fastvpinns +========== + +.. toctree:: + :maxdepth: 4 + + fastvpinns diff --git a/_sources/_rst/tutorials/forward_problems_2d/complex_mesh/cd2d/cd2d.rst.txt b/_sources/_rst/tutorials/forward_problems_2d/complex_mesh/cd2d/cd2d.rst.txt new file mode 100644 index 0000000..ab10f31 --- /dev/null +++ b/_sources/_rst/tutorials/forward_problems_2d/complex_mesh/cd2d/cd2d.rst.txt @@ -0,0 +1,832 @@ +Convection Diffusion 2D Example on Circular Domain +================================================== + + +This example demonstrates how to solve a Poisson equation in 2D on a circular domain using the ``fastvpinns`` package. +All the necessary files can be found in the examples folder of the `fastvpinns GitHub repository `_ + +The Poisson equation is given by + +.. math:: -\epsilon \nabla^2 u + \mathbf{b} \cdot \nabla u + cu = f \quad \text{in} \quad \Omega + +where :math:`\Omega` is the circular domain and :math:`f` is the source term. The boundary conditions are given by + +.. math:: + u = \cos(x^2 + y^2) \quad \text{on} \quad \partial \Omega + +For this problem, the parameters are + +.. math:: + :class: left-align + + f = 4x^2\cos(x^2 + y^2) - 2x\sin(x^2 + y^2) + 4y^2\cos(x^2 + y^2) + 4\sin(x^2 + y^2) + + \epsilon = 1, \mathbf{b} = [1, 0], c = 0 + +The exact solution is given by + +.. math:: u = cos(x^2 +y^2) + +Note : The forcing formulation for this problem is obtained by +substituting the exact solution into the cd2d equation with given pde +parameters. + +Computational Domain +^^^^^^^^^^^^^^^^^^^^ + +The computational domain is a circular domain with radius 1 centered at +(0, 0). + +.. figure:: mesh.png + :alt: alt text + +Contents +-------- + +- `Steps to run the code <#steps-to-run-the-code>`__ +- `Example File - cd2d_example.py `__ + + - `Defining the boundary + conditions <#defining-the-boundary-conditions>`__ + - `Defining the source term <#defining-the-source-term>`__ + - `Defining the exact solution <#defining-the-exact-solution>`__ + - `Defining the bilinear form <#defining-the-bilinear-form>`__ + +- `Input File <#input-file>`__ + + - `Experimentation parameters <#experimentation>`__ + - `Geometry parameters <#geometry>`__ + - `Finite element space parameters <#fe>`__ + - `PDE Beta parameters <#pde>`__ + - `Model parameters <#model>`__ + - `Logging parameters <#logging>`__ + +- `Main File - main_cd2d.py `__ + + - `Importing the required + libraries <#importing-the-required-libraries>`__ + - `imports from fastvpinns <#imports-from-fastvpinns>`__ + - `Reading the input file <#reading-the-input-file>`__ + - `Reading all input parameters <#reading-all-input-parameters>`__ + - `Set up the geometry <#set-up-the-geometry>`__ + - `Setup fespace <#setup-fespace>`__ + - `setup datahandler <#setup-datahandler>`__ + - `setup model <#setup-model>`__ + - `pre-train setup <#pre-train-setup>`__ + - `Training <#training>`__ + - `Post Training <#post-training>`__ + +- `Save the outputs <#save-the-outputs>`__ +- `Solution Plots <#solution-plots>`__ +- `References <#references>`__ + +Steps to run the code +---------------------- + +To run the code, execute the following command: + +.. code:: bash + + python3 main_cd2d.py input.yaml + +Example File - `cd2d_example.py `__ +-------------------------------------------------------------------------------------------------------------------------------------------------- + +This file hosts all the details about the bilinear parameters for the +PDE, boundary conditions, source term, and the exact solution. + +Defining the boundary conditions +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The function ``circle_boundary`` returns the boundary value for a given +component of the boundary. The function ``get_boundary_function_dict`` +returns a dictionary of boundary functions. The key of the dictionary is +the boundary id and the value is the boundary function. The function +``get_bound_cond_dict`` returns a dictionary of boundary conditions. The +key of the dictionary is the boundary id and the value is the boundary +condition. + +.. figure:: unitcircle.png + :alt: Unit Circle + :align: center + +For externally created geometries from gmsh, the user needs to provide +the physical tag for the boundaries present in the geometry. +In our case, we have used 1000 to define the circular boundary in mesh file. + +Note : As of now, only Dirichlet boundary conditions are supported. + +.. code:: python + + def circle_boundary(x, y): + """ + This function will return the boundary value for given component of a boundary + """ + return 0.0 + + def get_boundary_function_dict(): + """ + This function will return a dictionary of boundary functions + """ + return {1000: circle_boundary} + + + def get_bound_cond_dict(): + """ + This function will return a dictionary of boundary conditions + """ + return {1000: "dirichlet"} + +Defining the source term +~~~~~~~~~~~~~~~~~~~~~~~~ + +The function ``rhs`` returns the value of the source term at a given +point. + +.. code:: python + + 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 + +`Return to top <#contents>`__ + +Defining the exact solution +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The function ``exact_solution`` returns the value of the exact solution +at a given point. + +.. code:: python + + def exact_solution(x, y): + """ + This function will return the value of the exact solution at a given point + """ + u_temp = 16 * x * (1 - x) * y * (1 - y) + + return u_temp + +`Return to top <#contents>`__ + +Defining the bilinear form +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The function ``get_bilinear_params_dict`` returns a dictionary of +bilinear parameters. The dictionary contains the values of the +parameters :math:`\epsilon` (epsilon), :math:`b_x` (convection in +x-direction), :math:`b_y` (convection in y-direction), and :math:`c` +(reaction term). + +Note : If any of the bilinear parameters are not present in the +dictionary (for the cd2d model), then the code will throw an error. + +.. code:: python + + 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} + +`Return to top <#contents>`__ + +Input File +------------- + +This is the file that contains all the details about the problem. The +input file is in the YAML format. The input file for this example is +given below. The contents of the yaml files are as follows + +Experimentation +^^^^^^^^^^^^^^^ + +Defines the output path where the results will be saved. + +.. code:: yaml + + experimentation: + output_path: "output/cd2d/1" # Path to the output directory where the results will be saved. + +`Return to top <#contents>`__ + +Geometry +^^^^^^^^ + +It contains the details about the geometry of the domain. The mesh +generation method can be either “internal” or “external”. If the mesh +generation method is “internal”, then the ``internal_mesh_params`` are +used to generate the mesh. If the mesh generation method is “external”, +then the mesh is read from the file specified in the ``mesh_file`` +parameter. + +- In this case, we will use an external mesh. The mesh + ``../meshes/circle_quad.mesh`` is generated using the Gmsh software. + The mesh needs to have physical elements defined for the boundary. In + this case, the physical element is defined as 1000 (which is defined + in the ``circle_boundary`` function in the ``cd2d_example.py`` file). +- ``exact_solution_generation`` is set to “internal” which means that + the exact solution is generated using the ``exact_solution`` function + in the ``cd2d_example.py`` file. For external check the other + examples `cd2d_gear <../cd2d_gear/>`__ +- ``mesh_type`` is set to “quadrilateral” which means that the mesh is + a quadrilateral mesh. Note: As of now, only quadrilateral meshes are + supported. +- ``boundary_refinement_level`` is set to 4 which means that the + boundary is refined 4 times. (i.e), when the mesh is read, only the + boundary points of an edge in quadrilateral mesh are read. this + refinement will refine the boundary points to get more boundary + points within the edge. +- ``boundary_sampling_method`` is set to “uniform” which means that the + boundary points are sampled using the “uniform” method. (Use only + uniform sampling as of now.) +- ``generate_mesh_plot`` is set to True which means that the mesh plot + is generated and saved in the output directory. + +.. code:: yaml + + 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: "internal" # 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". + +`Return to top <#contents>`__ + +Finite Element Space +^^^^^^^^^^^^^^^^^^^^ + +This section contains the details about the finite element spaces. + +.. code:: yaml + + 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" + +Here the ``fe_order`` is set to 6 which means it has 6 basis functions +in each direction. The ``quad_order`` is set to 10 which means it uses a +10-points in each direction for the quadrature rule. The supported +quadrature rules are “gauss-jacobi” and “gauss-legendre”. In this +version of code, both “jacobi” and “legendre” refer to the same basis +functions (to maintain backward compatibility). The basis functions are +special type of Jacobi polynomials defined by + +.. math:: J_{n} = J_{n-1} - J_{n+1} + +, where J :sub:`n` is the nth Jacobi polynomial. + +`Return to top <#contents>`__ + +pde +^^^ + +This value provides the beta values for the Dirichlet boundary conditions. The beta values are the multipliers that are used to multiply the boundary losses. + +.. math:: + loss_{total} = loss_{pde} + \beta \cdot loss_{dirichlet} + +.. code:: yaml + + pde: + beta: 10 # Parameter for the PDE. + +`Return to top <#contents>`__ + +model +^^^^^ + +The model section contains the details about the dense model to be used. +The model architecture is given by the ``model_architecture`` parameter. +The activation function used in the model is given by the ``activation`` +parameter. The ``epochs`` parameter is the number of training epochs. +The ``dtype`` parameter is the data type used for computations. The +``learning_rate`` section contains the parameters for learning rate +scheduling. The ``initial_learning_rate`` parameter is the initial +learning rate. The ``use_lr_scheduler`` parameter is a flag indicating +whether to use the learning rate scheduler. The ``decay_steps`` +parameter is the number of steps between each learning rate decay. The +``decay_rate`` parameter is the decay rate for the learning rate. The +``staircase`` parameter is a flag indicating whether to use the +staircase decay. + +Any parameter which are not mentioned above are archived parameters, +which are not used in the current version of the code. (like +``use_attention``, ``set_memory_growth``) + +.. code:: yaml + + 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 + +`Return to top <#contents>`__ + +logging +^^^^^^^ + +``update_console_output`` defines the epochs at which you need to log +parameters like loss, time taken, etc. + +.. code:: yaml + + logging: + update_console_output: 100 # Number of epochs after which to update the console output. + +The other parameters such as ``update_progress_bar``, +``update_solution_images`` are archived parameters which are not used in +the current version of the code. + +`Return to top <#contents>`__ + +Main File - `main_cd2d.py `__ +----------------------------------------------------------------------------------------------------------------------------------------- + +This file contains the main code to solve the Poisson equation in 2D on +a circular domain. The code reads the input file, sets up the problem, +and solves the Poisson equation using the ``fastvpinns`` package. + +Importing the required libraries +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The following libraries are imported in the main file. + +.. code:: python + + 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 + +`Return to top <#contents>`__ + +imports from fastvpinns +^^^^^^^^^^^^^^^^^^^^^^^ + +The following imports are used from the ``fastvpinns`` package. + +- Imports the geometry module from the ``fastvpinns`` package, which + contains the ``Geometry_2D`` class responsible for setting up the + geometry of the domain. + +.. code:: python + + from fastvpinns.Geometry.geometry_2d import Geometry_2D + +- Imports the fespace module from the ``fastvpinns`` package, which + contains the ``FE`` class responsible for setting up the finite + element spaces. + +.. code:: python + + from fastvpinns.FE.fespace2d import Fespace2D + +- Imports the datahandler module from the ``fastvpinns`` package, which + contains the ``DataHandler`` class responsible for handling and + converting the data to necessary shape for training purposes + +.. code:: python + + from fastvpinns.DataHandler.datahandler import DataHandler + +- Imports the model module from the ``fastvpinns`` package, which + contains the ``Model`` class responsible for training the neural + network model. + +.. code:: python + + from fastvpinns.Model.model import DenseModel + +- Import the Loss module from the ``fastvpinns`` package, which + contains the loss function of the PDE to be solved in tensor form. + +.. code:: python + + from fastvpinns.physics.cd2d import pde_loss_cd2d + +- Import additional functionalities from the ``fastvpinns`` package. + +.. code:: python + + 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 + +`Return to top <#contents>`__ + +Reading the input file +^^^^^^^^^^^^^^^^^^^^^^ + +The input file is read using the ``yaml`` library. + +.. code:: python + + 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) + +Reading all input parameters +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code:: python + + # 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_console_output = config['logging']['update_console_output'] + +all the variables which are named with the prefix ``i_`` are input +parameters which are read from the input file. `Return to +top <#contents>`__ + +Set up the geometry +^^^^^^^^^^^^^^^^^^^ + +Obtain the bounndary condition and boundary values from the +``cd2d_example.py`` file and initialise the ``Geometry_2D`` class. After +that use the ``domain.read_mesh`` functionality to read the external +mesh file. + +.. code:: python + + cells, boundary_points = domain.read_mesh( + i_mesh_file_name, + i_boundary_refinement_level, + i_boundary_sampling_method, + refinement_level=1, + ) + +`Return to top <#contents>`__ + +Setup fespace +^^^^^^^^^^^^^ + +Initialise the ``Fespace2D`` class with the required parameters. + +.. code:: python + + 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, + ) + +`Return to top <#contents>`__ + +Setup datahandler +^^^^^^^^^^^^^^^^^ + +Initialise the ``DataHandler`` class with the required parameters. + +.. code:: python + + datahandler = DataHandler2D(fespace, domain, dtype=i_dtype) + +`Return to top <#contents>`__ + +Setup model +^^^^^^^^^^^ + +Setup the necessary parameters for the model and initialise the ``Model`` +class. Before that fill the ``params`` dictionary with the required +parameters. + +.. code:: python + + 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, + ) + +`Return to top <#contents>`__ + +Pre-train setup +^^^^^^^^^^^^^^^ + +.. code:: python + + 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) + +This sets up the test points and the exact solution. The progress bar is +initialised and the loss arrays are set up. The beta value is set up as +a constant tensor. `Return to top <#contents>`__ + +Training +^^^^^^^^ + +.. code:: python + + 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']) + +This ``train_step`` function trains the model for one epoch and returns +the loss. The loss is appended to the loss array. Then for every epoch +where +``(epoch + 1) % i_update_console_output == 0 or epoch == num_epochs - 1:`` + +.. code:: python + + 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}" + ) + +We will compute all the test errors and write the solution to a vtk file +for a complex mesh. Further, the console output will be printed with the +loss values and the test errors. `Return to top <#contents>`__ + +Post Training +^^^^^^^^^^^^^ + +.. code:: python + + # 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)) + +`Return to top <#contents>`__ + +This part of the code saves the model weights, writes the solution to a +vtk file, prints the error values in a table, prints the time values in +a table, and saves all the arrays as numpy arrays. + +save the outputs +---------------- + +All the outputs will be saved in the output directory specified in the +input file. The output directory will contain the following files: - +prediction_{epoch}.vtk : The solution file for each epoch. - +loss_function.txt : The loss function values for each epoch. - +prediction.txt : The predicted values at last epoch at the test points. +- exact.txt : The exact values at last epoch at the test points. - +error.txt : The error values at last epoch at the test points. - +time_per_epoch.txt : The time taken for each epoch. `Return to +top <#contents>`__ + +Solution Plots +----------------- + +.. figure:: exact_solution.png + :alt: Exact Solution + :align: center + + Exact Solution + +.. figure:: predicted_solution.png + :alt: Predicted Solution + :align: center + + Predicted Solution + +.. figure:: error.png + :alt: Error + :align: center + + +References +------------- + +1. `FastVPINNs: Tensor-Driven Acceleration of VPINNs for Complex + Geometries. `__ + +`Return to top <#contents>`__ diff --git a/_sources/_rst/tutorials/forward_problems_2d/complex_mesh/cd2d_gear/cd2d_gear.rst.txt b/_sources/_rst/tutorials/forward_problems_2d/complex_mesh/cd2d_gear/cd2d_gear.rst.txt new file mode 100644 index 0000000..2da2728 --- /dev/null +++ b/_sources/_rst/tutorials/forward_problems_2d/complex_mesh/cd2d_gear/cd2d_gear.rst.txt @@ -0,0 +1,839 @@ +Convection-Diffusion 2D Example on Circular Domain +================================================== + + +This example demonstrates how to solve a Poisson equation in 2D on a +circular domain using the ``fastvpinns`` package. +All the necessary files can be found in the examples folder of the `fastvpinns GitHub repository `_ +The Poisson equation is given by + +.. math:: -\epsilon \nabla^2 u + \mathbf{b} \cdot \nabla u + cu = f \quad \text{in} \quad \Omega + +where (:math:`\Omega`) is the circular domain and (f) is the source +term. The boundary conditions are given by + +.. math:: u = 0 \quad \text{on} \quad \partial \Omega + +For this problem, the parameters are + +.. math:: f = 50 \sin(x) + \cos(x) +.. math:: \epsilon = 1 +.. math:: \mathbf{b} = [0.1, 0] +.. math:: c = 0 + +The exact solution is computed using +`ParMOON `__, an inhouse FEM +package. + +Computational Domain +^^^^^^^^^^^^^^^^^^^^ + +The computational domain is a circular domain with radius 1 centered at +(0, 0). + +.. figure:: mesh.png + :alt: alt text + +Contents +----------- + +- `Steps to run the code <#steps-to-run-the-code>`__ +- `Example File - + cd2d_gear_example.py <#example-file---cd2d_gear_examplepy>`__ + + - `Defining the boundary + conditions <#defining-the-boundary-conditions>`__ + - `Defining the source term <#defining-the-source-term>`__ + - `Defining the exact solution <#defining-the-exact-solution>`__ + - `Defining the bilinear form <#defining-the-bilinear-form>`__ + +- `Input File <#input-file>`__ + + - `Experimentation parameters <#experimentation>`__ + - `Geometry parameters <#geometry>`__ + - `Finite element space parameters <#fe>`__ + - `PDE Beta parameters <#pde>`__ + - `Model parameters <#model>`__ + - `Logging parameters <#logging>`__ + +- `Main File - main_cd2d.py <#main-file---main_cd2dpy>`__ + + - `Importing the required + libraries <#importing-the-required-libraries>`__ + - `imports from fastvpinns <#imports-from-fastvpinns>`__ + - `Reading the input file <#reading-the-input-file>`__ + - `Reading all input parameters <#reading-all-input-parameters>`__ + - `Set up the geometry <#set-up-the-geometry>`__ + - `Setup fespace <#setup-fespace>`__ + - `setup datahandler <#setup-datahandler>`__ + - `setup model <#setup-model>`__ + - `pre-train setup <#pre-train-setup>`__ + - `Training <#training>`__ + - `Post Training <#post-training>`__ + +- `Save the outputs <#save-the-outputs>`__ +- `Solution Plots <#solution-plots>`__ + + - `Exact Solution <#exact-solution>`__ + - `Predicted Solution <#predicted-solution>`__ + - `Error Plot <#error-plot>`__ + +- `References <#references>`__ + +Steps to run the code +------------------------ + +To run the code, execute the following command: + +.. code:: bash + + python3 main_cd2d_gear.py input.yaml + +Example File - `cd2d_gear_example.py `__ +----------------------------------------------------------------------------------------------------------------------------------------------------------------- + +This file hosts all the details about the bilinear parameters for the +PDE, boundary conditions, source term, and the exact solution. + +Defining the boundary conditions +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The function ``get_boundary_function_dict`` returns a dictionary of +boundary functions. The key of the dictionary is the boundary id and the +value is the boundary function. The function ``get_bound_cond_dict`` +returns a dictionary of boundary conditions. The key of the dictionary +is the boundary id and the value is the boundary condition. + +here ``inner_boundary`` and ``outer_boundary`` are the functions which +return the boundary values for the inner and outer boundaries of the +gear geometry. The boundary ids are defined as 1000 and 1001 +respectively. The boundary conditions are defined as “dirichlet” for +both the boundaries. + +.. figure:: gmeshcircle.png + :alt: Gmesh Circle + :align: center + +For externally created geometries from gmsh, the user needs to provide +the physical tag for the boundaries present in the geometry. +In our case, we have used 1001, 1000 to define the internal and external boundary in mesh file. + +Note : As of now, only Dirichlet boundary conditions are supported. + +.. code:: python + + def inner_boundary(x, y): + """ + This function will return the boundary value for given component of a boundary + """ + return 0.0 + + + def outer_boundary(x, y): + """ + This function will return the boundary value for given component of a boundary + """ + + return 0.0 + + def get_boundary_function_dict(): + """ + This function will return a dictionary of boundary functions + """ + return {1000: outer_boundary, 1001: inner_boundary} + + + def get_bound_cond_dict(): + """ + This function will return a dictionary of boundary conditions + """ + return {1000: "dirichlet", 1001: "dirichlet"} + +Defining the source term +~~~~~~~~~~~~~~~~~~~~~~~~ + +The function ``rhs`` returns the value of the source term at a given +point. + +.. code:: python + + def rhs(x, y): + """ + This function will return the value of the rhs at a given point + """ + f_temp = 50 * np.sin(x) + np.cos(x) + + return f_temp + +`Return to top <#contents>`__ + +Defining the exact solution +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The function ``exact_solution`` returns the value of the exact solution +at a given point. + +**Note :Here the exact solution function does not matter, since the +exact solution will be read externally from a file, which contains the +fem solution to the problem.** + +.. code:: python + + def exact_solution(x, y): + """ + This function will return the exact solution at a given point + """ + r = np.sqrt(x**2 + y**2) + + return np.ones_like(x) * 0 + +`Return to top <#contents>`__ + +Defining the bilinear form +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The function ``get_bilinear_params_dict`` returns a dictionary of +bilinear parameters. The dictionary contains the values of the +parameters :math:`\epsilon` (epsilon), :math:`b_x` (convection) + +Note : If any of the bilinear parameters are not present in the +dictionary (for the cd2d model), then the code will throw an error. + +.. code:: python + + def get_bilinear_params_dict(): + """ + This function will return a dictionary of bilinear parameters + """ + eps = 1.0 + b_x = 0.1 + b_y = 0.0 + c = 0.0 + + return {"eps": eps, "b_x": b_x, "b_y": b_y, "c": c} + +`Return to top <#contents>`__ + +Input File +------------- + +This is the file that contains all the details about the problem. The +input file is in the YAML format. The input file for this example is +given below. The contents of the yaml files are as follows + +Experimentation +^^^^^^^^^^^^^^^ + +Defines the output path where the results will be saved. + +.. code:: yaml + + experimentation: + output_path: "output/cd2d_gear" # Path to the output directory where the results will be saved. + +`Return to top <#contents>`__ + +Geometry +^^^^^^^^ + +It contains the details about the geometry of the domain. The mesh +generation method can be either “internal” or “external”. If the mesh +generation method is “internal”, then the ``internal_mesh_params`` are +used to generate the mesh. If the mesh generation method is “external”, +then the mesh is read from the file specified in the ``mesh_file`` +parameter. + +- In this case, we will use an external mesh. The mesh + ``../meshes/circle_quad.mesh`` is generated using the Gmsh software. + The mesh needs to have physical elements defined for the boundary. In + this case, the physical element is defined as 1000 (which is defined + in the ``circle_boundary`` function in the ``cd2d_gear_example.py`` + file). +- ``exact_solution_generation`` is set to “external” which means that + the exact solution is read from an external file. +- ``mesh_type`` is set to “quadrilateral” which means that the mesh is + a quadrilateral mesh. Note: As of now, only quadrilateral meshes are + supported. +- ``boundary_refinement_level`` is set to 2 which means that the + boundary is refined 2 times. (i.e), when the mesh is read, only the + boundary points of an edge in quadrilateral mesh are read. this + refinement will refine the boundary points to get more boundary + points within the edge. +- ``boundary_sampling_method`` is set to “uniform” which means that the + boundary points are sampled using the “uniform” method. (Use only + uniform sampling as of now.) +- ``generate_mesh_plot`` is set to True which means that the mesh plot + is generated and saved in the output directory. + +.. code:: yaml + + geometry: + mesh_generation_method: "external" + generate_mesh_plot: False + internal_mesh_params: + x_min: 0 + x_max: 1 + y_min: 0 + y_max: 1 + n_cells_x: 8 + n_cells_y: 8 + n_boundary_points: 2000 + n_test_points_x: 100 + n_test_points_y: 100 + + exact_solution: + exact_solution_generation: "external" # whether the exact solution needs to be read from external file. + exact_solution_file_name: "fem_output_gear_forward_sin.csv" # External solution file name. + + mesh_type: "quadrilateral" + external_mesh_params: + mesh_file_name: "../meshes/gear.mesh" # should be a .mesh file + boundary_refinement_level: 2 + boundary_sampling_method: "uniform" # "uniform" + +`Return to top <#contents>`__ + +Finite Element Space +^^^^^^^^^^^^^^^^^^^^ + +This section contains the details about the finite element spaces. + +.. code:: yaml + + fe: + fe_order: 4 + fe_type: "jacobi" + quad_order: 5 + quad_type: "gauss-jacobi" + +Here the ``fe_order`` is set to 6 which means it has 6 basis functions +in each direction. The ``quad_order`` is set to 10 which means it uses a +10-points in each direction for the quadrature rule. The supported +quadrature rules are “gauss-jacobi” and “gauss-legendre”. In this +version of code, both “jacobi” and “legendre” refer to the same basis +functions (to maintain backward compatibility). The basis functions are +special type of Jacobi polynomials defined by + +.. math:: J_{n} = J_{n-1} - J_{n+1} + +, where J :sub:`n` is the nth Jacobi polynomial. + +`Return to top <#contents>`__ + +pde +^^^ + +This value provides the beta values for the dirichlet boundary +conditions. The beta values are the multipliers that are used to multiply +the boundary losses. $loss_{total} = loss_{pde} + \beta \cdot loss_{dirichlet}$ + +.. code:: yaml + + pde: + beta: 5 # Parameter for the PDE. + +`Return to top <#contents>`__ + +model +^^^^^ + +The model section contains the details about the dense model to be used. +The model architecture is given by the ``model_architecture`` parameter. +The activation function used in the model is given by the ``activation`` +parameter. The ``epochs`` parameter is the number of training epochs. +The ``dtype`` parameter is the data type used for computations. The +``learning_rate`` section contains the parameters for learning rate +scheduling. The ``initial_learning_rate`` parameter is the initial +learning rate. The ``use_lr_scheduler`` parameter is a flag indicating +whether to use the learning rate scheduler. The ``decay_steps`` +parameter is the number of steps between each learning rate decay. The +``decay_rate`` parameter is the decay rate for the learning rate. The +``staircase`` parameter is a flag indicating whether to use the +staircase decay. + +Any parameter which are not mentioned above are archived parameters, +which are not used in the current version of the code. (like +``use_attention``, ``set_memory_growth``) + +.. code:: yaml + + model: + model_architecture: [2, 50,50,50, 1] + activation: "tanh" + use_attention: False + epochs: 150000 + dtype: "float32" + set_memory_growth: False + learning_rate: + initial_learning_rate: 0.005 + use_lr_scheduler: True + decay_steps: 1000 + decay_rate: 0.99 + staircase: False + +`Return to top <#contents>`__ + +logging +^^^^^^^ + +``update_console_output`` defines the epochs at which you need to log +parameters like loss, time taken, etc. + +.. code:: yaml + + logging: + update_console_output: 10000 + +`Return to top <#contents>`__ + +Main File - `main_cd2d.py `__ +--------------------------------------------------- + +This file contains the main code to solve the Poisson equation in 2D on +a circular domain. The code reads the input file, sets up the problem, +and solves the Poisson equation using the ``fastvpinns`` package. + +Importing the required libraries +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The following libraries are imported in the main file. + +.. code:: python + + 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 + +`Return to top <#contents>`__ + +imports from fastvpinns +^^^^^^^^^^^^^^^^^^^^^^^ + +The following imports are used from the ``fastvpinns`` package. + +- Imports the geometry module from the ``fastvpinns`` package, which + contains the ``Geometry_2D`` class responsible for setting up the + geometry of the domain. + +.. code:: python + + from fastvpinns.Geometry.geometry_2d import Geometry_2D + +- Imports the fespace module from the ``fastvpinns`` package, which + contains the ``FE`` class responsible for setting up the finite + element spaces. + +.. code:: python + + from fastvpinns.FE.fespace2d import Fespace2D + +- Imports the datahandler module from the ``fastvpinns`` package, which + contains the ``DataHandler`` class responsible for handling and + converting the data to necessary shape for training purposes + +.. code:: python + + from fastvpinns.DataHandler.datahandler import DataHandler + +- Imports the model module from the ``fastvpinns`` package, which + contains the ``Model`` class responsible for training the neural + network model. + +.. code:: python + + from fastvpinns.Model.model import DenseModel + +- Import the Loss module from the ``fastvpinns`` package, which + contains the loss function of the PDE to be solved in tensor form. + +.. code:: python + + from fastvpinns.physics.cd2d import pde_loss_cd2d + +- Import additional functionalities from the ``fastvpinns`` package. + +.. code:: python + + 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 + +`Return to top <#contents>`__ + +Reading the input file +^^^^^^^^^^^^^^^^^^^^^^ + +The input file is read using the ``yaml`` library. + +.. code:: python + + 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) + +Reading all input parameters +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code:: python + + # 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_console_output = config['logging']['update_console_output'] + +all the variables which are named with the prefix ``i_`` are input +parameters which are read from the input file. `Return to +top <#contents>`__ + +Set up the geometry +^^^^^^^^^^^^^^^^^^^ + +Obtain the bounndary condition and boundary values from the +``cd2d_gear_example.py`` file and initialise the ``Geometry_2D`` class. +After that use the ``domain.read_mesh`` functionality to read the +external mesh file. + +.. code:: python + + cells, boundary_points = domain.read_mesh( + i_mesh_file_name, + i_boundary_refinement_level, + i_boundary_sampling_method, + refinement_level=1, + ) + +`Return to top <#contents>`__ + +Setup fespace +^^^^^^^^^^^^^ + +Initialise the ``Fespace2D`` class with the required parameters. + +.. code:: python + + 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, + ) + +`Return to top <#contents>`__ + +Setup datahandler +^^^^^^^^^^^^^^^^^ + +Initialise the ``DataHandler`` class with the required parameters. + +.. code:: python + + datahandler = DataHandler2D(fespace, domain, dtype=i_dtype) + +`Return to top <#contents>`__ + +Setup model +^^^^^^^^^^^ + +Setup the necessary parameters for the model and initialise the ``Model`` +class. Before that fill the ``params`` dictionary with the required +parameters. + +.. code:: python + + model = DenseModel( + layer_dims=i_model_architecture, + 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, + ) + +`Return to top <#contents>`__ + +Pre-train setup +^^^^^^^^^^^^^^^ + +.. code:: python + + if i_exact_solution_generation == "internal": + y_exact = exact_solution(test_points[:, 0], test_points[:, 1]) + else: + exact_db = pd.read_csv(f"{i_exact_solution_file_name}", header=None, delimiter=",") + y_exact = exact_db.iloc[:, 2].values.reshape(-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) + +Here the exact solution is being read from the external file. The +external solution at the test points is computed by FEM and stored in a +csv file. This sets up the test points and the exact solution. The +progress bar is initialised and the loss arrays are set up. The beta +value is set up as a constant tensor. `Return to top <#contents>`__ + +Training +^^^^^^^^ + +.. code:: python + + 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']) + +This ``train_step`` function trains the model for one epoch and returns +the loss. The loss is appended to the loss array. Then for every epoch +where +``(epoch + 1) % i_update_console_output == 0 or epoch == num_epochs - 1:`` + +.. code:: python + + 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}" + ) + +We will compute all the test errors and write the solution to a vtk file +for a complex mesh. Further, the console output will be printed with the +loss values and the test errors. `Return to top <#contents>`__ + +Post Training +^^^^^^^^^^^^^ + +.. code:: python + + # 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)) + +`Return to top <#contents>`__ + +This part of the code saves the model weights, writes the solution to a +vtk file, prints the error values in a table, prints the time values in +a table, and saves all the arrays as numpy arrays. + +save the outputs +---------------- + +All the outputs will be saved in the output directory specified in the +input file. The output directory will contain the following files: - +prediction_{epoch}.vtk : The solution file for each epoch. - +loss_function.txt : The loss function values for each epoch. - +prediction.txt : The predicted values at last epoch at the test points. +- exact.txt : The exact values at last epoch at the test points. - +error.txt : The error values at last epoch at the test points. - +time_per_epoch.txt : The time taken for each epoch. `Return to +top <#contents>`__ + +Solution Plots +--------------- +.. figure:: exact_solution.png + :alt: Exact Solution + :align: center + + Exact Solution + +.. figure:: predicted_solution.png + :alt: Predicted Solution + :align: center + + Predicted Solution + +.. figure:: error.png + :alt: Error + :align: center + + Error + +References +------------- + +1. `FastVPINNs: Tensor-Driven Acceleration of VPINNs for Complex + Geometries. `__ + +`Return to top <#contents>`__ diff --git a/_sources/_rst/tutorials/forward_problems_2d/complex_mesh/helmholtz2d/helmholtz2d.rst.txt b/_sources/_rst/tutorials/forward_problems_2d/complex_mesh/helmholtz2d/helmholtz2d.rst.txt new file mode 100644 index 0000000..192bafd --- /dev/null +++ b/_sources/_rst/tutorials/forward_problems_2d/complex_mesh/helmholtz2d/helmholtz2d.rst.txt @@ -0,0 +1,839 @@ +Helmholtz 2D Example on Circular Domain +======================================= + + +This example demonstrates how to solve a Poisson equation in 2D on a +circular domain using the ``fastvpinns`` package. +All the necessary files can be found in the examples folder of the `fastvpinns GitHub repository `_ + +The Poisson equation is given by + +.. math:: -\epsilon \nabla^2 u + k^2u = f \quad \text{in} \quad \Omega + +where (:math:`\Omega`) is the circular domain and (f) is the source +term. The boundary conditions are given by + +.. math:: u = (x + y) * sin(\pi * x) * sin(\pi * y) \quad \text{on} \quad \partial \Omega + +For this problem, the parameters are + +.. math:: f = 2 \pi \cos(\pi y) \sin(\pi x) + 2 \pi \cos(\pi x) \sin(\pi y) + (x+y) \sin(\pi x) \sin(\pi y) - \\ + 2 \pi^2 (x+y) \sin(\pi x) \sin(\pi y) + +.. math:: \epsilon = 1.0 + +.. math:: k = 1.0 + +The exact solution is given by + +.. math:: u = (x + y) * sin(\pi * x) * sin(\pi * y) + +Computational Domain +^^^^^^^^^^^^^^^^^^^^ + +The computational domain is a circular domain with radius 1 centered at +(0, 0). + +.. figure:: mesh.png + :alt: alt text + +Contents +----------- + +- `Steps to run the code <#steps-to-run-the-code>`__ +- `Example File - + helmholtz_example.py <#example-file---helmholtz_examplepy>`__ + + - `Defining the boundary + conditions <#defining-the-boundary-conditions>`__ + - `Defining the source term <#defining-the-source-term>`__ + - `Defining the exact solution <#defining-the-exact-solution>`__ + - `Defining the bilinear form <#defining-the-bilinear-form>`__ + +- `Input File <#input-file>`__ + + - `Experimentation parameters <#experimentation>`__ + - `Geometry parameters <#geometry>`__ + - `Finite element space parameters <#fe>`__ + - `PDE Beta parameters <#pde>`__ + - `Model parameters <#model>`__ + - `Logging parameters <#logging>`__ + +- `Main File - main_helmholtz.py <#main-file---main_helmholtzpy>`__ + + - `Importing the required + libraries <#importing-the-required-libraries>`__ + - `imports from fastvpinns <#imports-from-fastvpinns>`__ + - `Reading the input file <#reading-the-input-file>`__ + - `Reading all input parameters <#reading-all-input-parameters>`__ + - `Set up the geometry <#set-up-the-geometry>`__ + - `Setup fespace <#setup-fespace>`__ + - `setup datahandler <#setup-datahandler>`__ + - `setup model <#setup-model>`__ + - `pre-train setup <#pre-train-setup>`__ + - `Training <#training>`__ + - `Post Training <#post-training>`__ + +- `Save the outputs <#save-the-outputs>`__ +- `Solution Plots <#solution-plots>`__ + + - `Exact Solution <#exact-solution>`__ + - `Predicted Solution <#predicted-solution>`__ + - `Error Plot <#error-plot>`__ + +- `References <#references>`__ + +Steps to run the code +------------------------ + +To run the code, execute the following command: + +.. code:: bash + + python3 main_helmholtz.py input.yaml + +Example File - `helmholtz_example.py `__ +----------------------------------------------------------------- + +This file hosts all the details about the bilinear parameters for the +PDE, boundary conditions, source term, and the exact solution. + +Defining the boundary conditions +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The function ``circle_boundary`` returns the boundary value for a given +component of the boundary. The function ``get_boundary_function_dict`` +returns a dictionary of boundary functions. The key of the dictionary is +the boundary id and the value is the boundary function. The function +``get_bound_cond_dict`` returns a dictionary of boundary conditions. The +key of the dictionary is the boundary id and the value is the boundary +condition. + +.. figure:: unitcircle.png + :alt: Unit Circle + :align: center + +For externally created geometries from gmsh, the user needs to provide +the physical tag for the boundaries present in the geometry. +In our case, we have used 1000 to define the circular boundary in mesh file. + +Note : As of now, only Dirichlet boundary conditions are supported. + +.. code:: python + + def circle_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 get_boundary_function_dict(): + """ + This function will return a dictionary of boundary functions + """ + return {1000: circle_boundary} + + + def get_bound_cond_dict(): + """ + This function will return a dictionary of boundary conditions + """ + return {1000: "dirichlet"} + +Defining the source term +~~~~~~~~~~~~~~~~~~~~~~~~ + +The function ``rhs`` returns the value of the source term at a given +point. + +.. code:: python + + 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 + +`Return to top <#contents>`__ + +Defining the exact solution +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The function ``exact_solution`` returns the value of the exact solution +at a given point. + +.. code:: python + + 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) + +`Return to top <#contents>`__ + +Defining the bilinear form +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The function ``get_bilinear_params_dict`` returns a dictionary of +bilinear parameters. The dictionary contains the values of the +parameters (:math:`\epsilon`), (b_x), (b_y), and (c). + +Note : If any of the bilinear parameters are not present in the +dictionary (for the cd2d model), then the code will throw an error. + +.. code:: python + + 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} + +`Return to top <#contents>`__ + +Input File +------------- + +This is the file that contains all the details about the problem. The +input file is in the YAML format. The input file for this example is +given below. The contents of the yaml files are as follows + +Experimentation +^^^^^^^^^^^^^^^ + +Defines the output path where the results will be saved. + +.. code:: yaml + + experimentation: + output_path: "output/helmholtz/1" + +`Return to top <#contents>`__ + +Geometry +^^^^^^^^ + +It contains the details about the geometry of the domain. The mesh +generation method can be either “internal” or “external”. If the mesh +generation method is “internal”, then the ``internal_mesh_params`` are +used to generate the mesh. If the mesh generation method is “external”, +then the mesh is read from the file specified in the ``mesh_file`` +parameter. + +- In this case, we will use an external mesh. The mesh + ``../meshes/circle_quad.mesh`` is generated using the Gmsh software. + The mesh needs to have physical elements defined for the boundary. In + this case, the physical element is defined as 1000 (which is defined + in the ``circle_boundary`` function in the ``helmholtz_example.py`` + file). +- ``exact_solution_generation`` is set to “internal” which means that + the exact solution is generated using the ``exact_solution`` function + in the ``helmholtz_example.py`` file. For external check the other + examples `cd2d_gear <../cd2d_gear/>`__ +- ``mesh_type`` is set to “quadrilateral” which means that the mesh is + a quadrilateral mesh. Note: As of now, only quadrilateral meshes are + supported. +- ``boundary_refinement_level`` is set to 4 which means that the + boundary is refined 4 times. (i.e), when the mesh is read, only the + boundary points of an edge in quadrilateral mesh are read. this + refinement will refine the boundary points to get more boundary + points within the edge. +- ``boundary_sampling_method`` is set to “uniform” which means that the + boundary points are sampled using the “uniform” method. (Use only + uniform sampling as of now.) +- ``generate_mesh_plot`` is set to True which means that the mesh plot + is generated and saved in the output directory. + +.. code:: yaml + + 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: "internal" # 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". + +`Return to top <#contents>`__ + +Finite Element Space +^^^^^^^^^^^^^^^^^^^^ + +This section contains the details about the finite element spaces. + +.. code:: yaml + + fe: + fe_order: 4 # Order of the finite element basis functions. + fe_type: "jacobi" # Type of finite element basis functions. + quad_order: 5 # Order of the quadrature rule. + quad_type: "gauss-jacobi" # Type of quadrature rule. + +Here the ``fe_order`` is set to 6 which means it has 6 basis functions +in each direction. The ``quad_order`` is set to 10 which means it uses a +10-points in each direction for the quadrature rule. The supported +quadrature rules are “gauss-jacobi” and “gauss-legendre”. In this +version of code, both “jacobi” and “legendre” refer to the same basis +functions (to maintain backward compatibility). The basis functions are +special type of Jacobi polynomials defined by + +.. math:: J_{n} = J_{n-1} - J_{n+1} + +, where J :sub:`n` is the nth Jacobi polynomial. + +`Return to top <#contents>`__ + +pde +^^^ + +This value provides the beta values for the Dirichlet boundary conditions. The beta values are the multipliers that are used to multiply the boundary losses. The total loss is calculated as follows: + +.. math:: loss_{total} = loss_{pde} + \beta \cdot loss_{dirichlet} + +.. code:: yaml + + pde: + beta: 10 # Parameter for the PDE. + +`Return to top <#contents>`__ + +model +^^^^^ + +The model section contains the details about the dense model to be used. +The model architecture is given by the ``model_architecture`` parameter. +The activation function used in the model is given by the ``activation`` +parameter. The ``epochs`` parameter is the number of training epochs. +The ``dtype`` parameter is the data type used for computations. The +``learning_rate`` section contains the parameters for learning rate +scheduling. The ``initial_learning_rate`` parameter is the initial +learning rate. The ``use_lr_scheduler`` parameter is a flag indicating +whether to use the learning rate scheduler. The ``decay_steps`` +parameter is the number of steps between each learning rate decay. The +``decay_rate`` parameter is the decay rate for the learning rate. The +``staircase`` parameter is a flag indicating whether to use the +staircase decay. + +Any parameter which are not mentioned above are archived parameters, +which are not used in the current version of the code. (like +``use_attention``, ``set_memory_growth``) + +.. code:: yaml + + model: + model_architecture: [2, 30,30,30, 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. + + +`Return to top <#contents>`__ + +logging +^^^^^^^ + +``update_console_output`` defines the epochs at which you need to log +parameters like loss, time taken, etc. + +.. code:: yaml + + logging: + update_console_output: 5000 + +`Return to top <#contents>`__ + +Main File - `main_helmholtz.py `__ +-------------------------------------------------------- + +This file contains the main code to solve the Poisson equation in 2D on +a circular domain. The code reads the input file, sets up the problem, +and solves the Poisson equation using the ``fastvpinns`` package. + +Importing the required libraries +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The following libraries are imported in the main file. + +.. code:: python + + 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 + +`Return to top <#contents>`__ + +imports from fastvpinns +^^^^^^^^^^^^^^^^^^^^^^^ + +The following imports are used from the ``fastvpinns`` package. + +- Imports the geometry module from the ``fastvpinns`` package, which + contains the ``Geometry_2D`` class responsible for setting up the + geometry of the domain. + +.. code:: python + + from fastvpinns.Geometry.geometry_2d import Geometry_2D + +- Imports the fespace module from the ``fastvpinns`` package, which + contains the ``FE`` class responsible for setting up the finite + element spaces. + +.. code:: python + + from fastvpinns.FE.fespace2d import Fespace2D + +- Imports the datahandler module from the ``fastvpinns`` package, which + contains the ``DataHandler`` class responsible for handling and + converting the data to necessary shape for training purposes + +.. code:: python + + from fastvpinns.DataHandler.datahandler import DataHandler + +- Imports the model module from the ``fastvpinns`` package, which + contains the ``Model`` class responsible for training the neural + network model. + +.. code:: python + + from fastvpinns.Model.model import DenseModel + +- Import the Loss module from the ``fastvpinns`` package, which + contains the loss function of the PDE to be solved in tensor form. + +.. code:: python + + from fastvpinns.physics.helmholtz2d import pde_loss_helmholtz + +- Import additional functionalities from the ``fastvpinns`` package. + +.. code:: python + + 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 + +`Return to top <#contents>`__ + +Reading the input file +^^^^^^^^^^^^^^^^^^^^^^ + +The input file is read using the ``yaml`` library. + +.. code:: python + + 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) + +Reading all input parameters +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code:: python + + # 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_console_output = config['logging']['update_console_output'] + +all the variables which are named with the prefix ``i_`` are input +parameters which are read from the input file. `Return to +top <#contents>`__ + +Set up the geometry +^^^^^^^^^^^^^^^^^^^ + +Obtain the bounndary condition and boundary values from the +``helmholtz_example.py`` file and initialise the ``Geometry_2D`` class. +After that use the ``domain.read_mesh`` functionality to read the +external mesh file. + +.. code:: python + + cells, boundary_points = domain.read_mesh( + i_mesh_file_name, + i_boundary_refinement_level, + i_boundary_sampling_method, + refinement_level=1, + ) + +`Return to top <#contents>`__ + +Setup fespace +^^^^^^^^^^^^^ + +Initialise the ``Fespace2D`` class with the required parameters. + +.. code:: python + + 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, + ) + +`Return to top <#contents>`__ + +Setup datahandler +^^^^^^^^^^^^^^^^^ + +Initialise the ``DataHandler`` class with the required parameters. + +.. code:: python + + datahandler = DataHandler2D(fespace, domain, dtype=i_dtype) + +`Return to top <#contents>`__ + +Setup model +^^^^^^^^^^^ + +Setup the necessary parameters for the model and initialise the ``Model`` +class. Before that fill the ``params`` dictionary with the required +parameters. + +.. code:: python + + model = DenseModel( + layer_dims=i_model_architecture, + 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, + ) + +`Return to top <#contents>`__ + +Pre-train setup +^^^^^^^^^^^^^^^ + +.. code:: python + + 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) + +Here the exact solution is being read from the external file. The +external solution at the test points is computed by FEM and stored in a +csv file. This sets up the test points and the exact solution. The +progress bar is initialised and the loss arrays are set up. The beta +value is set up as a constant tensor. `Return to top <#contents>`__ + +Training +^^^^^^^^ + +.. code:: python + + 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']) + +This ``train_step`` function trains the model for one epoch and returns +the loss. The loss is appended to the loss array. Then for every epoch +where +``(epoch + 1) % i_update_console_output == 0 or epoch == num_epochs - 1:`` + +.. code:: python + + 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}" + ) + +We will compute all the test errors and write the solution to a vtk file +for a complex mesh. Further, the console output will be printed with the +loss values and the test errors. `Return to top <#contents>`__ + +Post Training +^^^^^^^^^^^^^ + +.. code:: python + + # 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)) + +`Return to top <#contents>`__ + +This part of the code saves the model weights, writes the solution to a +vtk file, prints the error values in a table, prints the time values in +a table, and saves all the arrays as numpy arrays. + +save the outputs +---------------- + +All the outputs will be saved in the output directory specified in the +input file. The output directory will contain the following files: - +prediction_{epoch}.vtk : The solution file for each epoch. - +loss_function.txt : The loss function values for each epoch. - +prediction.txt : The predicted values at last epoch at the test points. +- exact.txt : The exact values at last epoch at the test points. - +error.txt : The error values at last epoch at the test points. - +time_per_epoch.txt : The time taken for each epoch. + +`Return to top <#contents>`__ + +Solution Plots +----------------- +.. figure:: exact_solution.png + :alt: Exact Solution + :align: center + + Exact Solution + +.. figure:: predicted_solution.png + :alt: Predicted Solution + :align: center + + Predicted Solution + +.. figure:: error.png + :alt: Error + :align: center + + Error + + +References +------------- + +1. `FastVPINNs: Tensor-Driven Acceleration of VPINNs for Complex + Geometries. `__ + +`Return to top <#contents>`__ diff --git a/_sources/_rst/tutorials/forward_problems_2d/complex_mesh/poisson2d/poisson2d.rst.txt b/_sources/_rst/tutorials/forward_problems_2d/complex_mesh/poisson2d/poisson2d.rst.txt new file mode 100644 index 0000000..48d4ccd --- /dev/null +++ b/_sources/_rst/tutorials/forward_problems_2d/complex_mesh/poisson2d/poisson2d.rst.txt @@ -0,0 +1,831 @@ +Poisson 2D Example on Circular Domain +===================================== + + +This example demonstrates how to solve a Poisson equation in 2D on a +circular domain using the ``fastvpinns`` package. +All the necessary files can be found in the examples folder of the `fastvpinns GitHub repository `_ + +The Poisson equation is given by + +.. math:: -\epsilon \nabla^2 u = f \quad \text{in} \quad \Omega + +where (:math:`\Omega`) is the circular domain and (f) is the source +term. The boundary conditions are given by + +.. math:: u = -1.0 * sin( 2 \pi x) * sin( 2 \pi y) \quad \text{on} \quad \partial \Omega + +For this problem, the parameters are + +.. math:: f = -2.0 \cdot (2 \pi x) \cdot (\sin(2 \pi x) \cdot \sin(2 \pi y)) +.. math:: \epsilon = 1 + +The exact solution is given by + +.. math:: u = -1.0 * sin( 2 \pi x) * sin( 2 \pi y) + +Computational Domain +^^^^^^^^^^^^^^^^^^^^ + +The computational domain is a circular domain with radius 1 centered at +(0, 0). + +.. figure:: mesh.png + :alt: alt text + +Contents +----------- + +- `Steps to run the code <#steps-to-run-the-code>`__ +- `Example File - sin_cos.py <#example-file---helmholtz_examplepy>`__ + + - `Defining the boundary + conditions <#defining-the-boundary-conditions>`__ + - `Defining the source term <#defining-the-source-term>`__ + - `Defining the exact solution <#defining-the-exact-solution>`__ + - `Defining the bilinear form <#defining-the-bilinear-form>`__ + +- `Input File <#input-file>`__ + + - `Experimentation parameters <#experimentation>`__ + - `Geometry parameters <#geometry>`__ + - `Finite element space parameters <#fe>`__ + - `PDE Beta parameters <#pde>`__ + - `Model parameters <#model>`__ + - `Logging parameters <#logging>`__ + +- `Main File - main_poisson2d.py <#main-file---main_helmholtzpy>`__ + + - `Importing the required + libraries <#importing-the-required-libraries>`__ + - `imports from fastvpinns <#imports-from-fastvpinns>`__ + - `Reading the input file <#reading-the-input-file>`__ + - `Reading all input parameters <#reading-all-input-parameters>`__ + - `Set up the geometry <#set-up-the-geometry>`__ + - `Setup fespace <#setup-fespace>`__ + - `setup datahandler <#setup-datahandler>`__ + - `setup model <#setup-model>`__ + - `pre-train setup <#pre-train-setup>`__ + - `Training <#training>`__ + - `Post Training <#post-training>`__ + +- `Save the outputs <#save-the-outputs>`__ +- `Solution Plots <#solution-plots>`__ + + - `Exact Solution <#exact-solution>`__ + - `Predicted Solution <#predicted-solution>`__ + - `Error Plot <#error-plot>`__ + +- `References <#references>`__ + +Steps to run the code +------------------------ + +To run the code, execute the following command: + +.. code:: bash + + python3 main_poisson2d.py input.yaml + +Example File - `sin_cos.py `__ +--------------------------------------------- + +This file hosts all the details about the bilinear parameters for the +PDE, boundary conditions, source term, and the exact solution. + +Defining the boundary conditions +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The function ``circle_boundary`` returns the boundary value for a given +component of the boundary. The function ``get_boundary_function_dict`` +returns a dictionary of boundary functions. The key of the dictionary is +the boundary id and the value is the boundary function. The function +``get_bound_cond_dict`` returns a dictionary of boundary conditions. The +key of the dictionary is the boundary id and the value is the boundary +condition. + +.. figure:: unitcircle.png + :alt: Unit Circle + :align: center + +For externally created geometries from gmsh, the user needs to provide +the physical tag for the boundaries present in the geometry. +In our case, we have used 1000 to define the circular boundary in mesh file. + +Note : As of now, only Dirichlet boundary conditions are supported. + +.. code:: python + + def circle_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 get_boundary_function_dict(): + """ + This function will return a dictionary of boundary functions + """ + return {1000: circle_boundary} + + def get_bound_cond_dict(): + """ + This function will return a dictionary of boundary conditions + """ + return {1000: "dirichlet"} + +Defining the source term +~~~~~~~~~~~~~~~~~~~~~~~~ + +The function ``rhs`` returns the value of the source term at a given +point. + +.. code:: python + + 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 + +`Return to top <#contents>`__ + +Defining the exact solution +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The function ``exact_solution`` returns the value of the exact solution +at a given point. + +.. code:: python + + 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 + +`Return to top <#contents>`__ + +Defining the bilinear form +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The function ``get_bilinear_params_dict`` returns a dictionary of +bilinear parameters. The dictionary contains the values of the +parameters :math:`\epsilon` (diffusion coefficient). + +Note : If any of the bilinear parameters are not present in the +dictionary (for the cd2d model), then the code will throw an error. + +.. code:: python + + def get_bilinear_params_dict(): + """ + This function will return a dictionary of bilinear parameters + """ + eps = 1.0 + + return {"eps": eps} + +`Return to top <#contents>`__ + +Input File +------------- + +This is the file that contains all the details about the problem. The +input file is in the YAML format. The input file for this example is +given below. The contents of the yaml files are as follows + +Experimentation +^^^^^^^^^^^^^^^ + +Defines the output path where the results will be saved. + +.. code:: yaml + + experimentation: + output_path: "output/helmholtz/1" + +`Return to top <#contents>`__ + +Geometry +^^^^^^^^ + +It contains the details about the geometry of the domain. The mesh +generation method can be either “internal” or “external”. If the mesh +generation method is “internal”, then the ``internal_mesh_params`` are +used to generate the mesh. If the mesh generation method is “external”, +then the mesh is read from the file specified in the ``mesh_file`` +parameter. + +- In this case, we will use an external mesh. The mesh + ``../meshes/circle_quad.mesh`` is generated using the Gmsh software. + The mesh needs to have physical elements defined for the boundary. In + this case, the physical element is defined as 1000 (which is defined + in the ``circle_boundary`` function in the ``sin_cos.py`` file). +- ``exact_solution_generation`` is set to “internal” which means that + the exact solution is generated using the ``exact_solution`` function + in the ``sin_cos.py`` file. For external check the other examples + `cd2d_gear <../cd2d_gear/>`__ +- ``mesh_type`` is set to “quadrilateral” which means that the mesh is + a quadrilateral mesh. Note: As of now, only quadrilateral meshes are + supported. +- ``boundary_refinement_level`` is set to 4 which means that the + boundary is refined 4 times. (i.e), when the mesh is read, only the + boundary points of an edge in quadrilateral mesh are read. this + refinement will refine the boundary points to get more boundary + points within the edge. +- ``boundary_sampling_method`` is set to “uniform” which means that the + boundary points are sampled using the “uniform” method. (Use only + uniform sampling as of now.) +- ``generate_mesh_plot`` is set to True which means that the mesh plot + is generated and saved in the output directory. + +.. code:: yaml + + 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: "internal" # 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". + +`Return to top <#contents>`__ + +Finite Element Space +^^^^^^^^^^^^^^^^^^^^ + +This section contains the details about the finite element spaces. + +.. code:: yaml + + 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. + +Here the ``fe_order`` is set to 6 which means it has 6 basis functions +in each direction. The ``quad_order`` is set to 10 which means it uses a +10-points in each direction for the quadrature rule. The supported +quadrature rules are “gauss-jacobi” and “gauss-legendre”. In this +version of code, both “jacobi” and “legendre” refer to the same basis +functions (to maintain backward compatibility). The basis functions are +special type of Jacobi polynomials defined by + +.. math:: J_{n} = J_{n-1} - J_{n+1} + +, where J :sub:`n` is the nth Jacobi polynomial. + +`Return to top <#contents>`__ + +pde +^^^ + +This value provides the beta values for the Dirichlet boundary conditions. The beta values are the multipliers that are used to multiply the boundary losses. The total loss is calculated as the sum of the PDE loss and the Dirichlet boundary loss, weighted by the beta values: + +.. math:: loss_{total} = loss_{pde} + \beta \cdot loss_{dirichlet} + +.. code:: yaml + + pde: + beta: 10 # Parameter for the PDE. + +`Return to top <#contents>`__ + +model +^^^^^ + +The model section contains the details about the dense model to be used. +The model architecture is given by the ``model_architecture`` parameter. +The activation function used in the model is given by the ``activation`` +parameter. The ``epochs`` parameter is the number of training epochs. +The ``dtype`` parameter is the data type used for computations. The +``learning_rate`` section contains the parameters for learning rate +scheduling. The ``initial_learning_rate`` parameter is the initial +learning rate. The ``use_lr_scheduler`` parameter is a flag indicating +whether to use the learning rate scheduler. The ``decay_steps`` +parameter is the number of steps between each learning rate decay. The +``decay_rate`` parameter is the decay rate for the learning rate. The +``staircase`` parameter is a flag indicating whether to use the +staircase decay. + +Any parameter which are not mentioned above are archived parameters, +which are not used in the current version of the code. (like +``use_attention``, ``set_memory_growth``) + +.. code:: yaml + + model: + model_architecture: [2, 30, 30, 30, 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: 5000 # 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. + +`Return to top <#contents>`__ + +logging +^^^^^^^ + +``update_console_output`` defines the epochs at which you need to log +parameters like loss, time taken, etc. + +.. code:: yaml + + logging: + update_console_output: 2000 + +`Return to top <#contents>`__ + +Main File - `main_poisson2d.py `__ +-------------------------------------------------------- + +This file contains the main code to solve the Poisson equation in 2D on +a circular domain. The code reads the input file, sets up the problem, +and solves the Poisson equation using the ``fastvpinns`` package. + +Importing the required libraries +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The following libraries are imported in the main file. + +.. code:: python + + 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 + +`Return to top <#contents>`__ + +imports from fastvpinns +^^^^^^^^^^^^^^^^^^^^^^^ + +The following imports are used from the ``fastvpinns`` package. + +- Imports the geometry module from the ``fastvpinns`` package, which + contains the ``Geometry_2D`` class responsible for setting up the + geometry of the domain. + +.. code:: python + + from fastvpinns.Geometry.geometry_2d import Geometry_2D + +- Imports the fespace module from the ``fastvpinns`` package, which + contains the ``FE`` class responsible for setting up the finite + element spaces. + +.. code:: python + + from fastvpinns.FE.fespace2d import Fespace2D + +- Imports the datahandler module from the ``fastvpinns`` package, which + contains the ``DataHandler`` class responsible for handling and + converting the data to necessary shape for training purposes + +.. code:: python + + from fastvpinns.DataHandler.datahandler import DataHandler + +- Imports the model module from the ``fastvpinns`` package, which + contains the ``Model`` class responsible for training the neural + network model. + +.. code:: python + + from fastvpinns.Model.model import DenseModel + +- Import the Loss module from the ``fastvpinns`` package, which + contains the loss function of the PDE to be solved in tensor form. + +.. code:: python + + from fastvpinns.physics.helmholtz2d import pde_loss_helmholtz + +- Import additional functionalities from the ``fastvpinns`` package. + +.. code:: python + + 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 + +`Return to top <#contents>`__ + +Reading the input file +^^^^^^^^^^^^^^^^^^^^^^ + +The input file is read using the ``yaml`` library. + +.. code:: python + + 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) + +Reading all input parameters +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code:: python + + # 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_console_output = config['logging']['update_console_output'] + +all the variables which are named with the prefix ``i_`` are input +parameters which are read from the input file. `Return to +top <#contents>`__ + +Set up the geometry +^^^^^^^^^^^^^^^^^^^ + +Obtain the bounndary condition and boundary values from the +``sin_cos.py`` file and initialise the ``Geometry_2D`` class. After that +use the ``domain.read_mesh`` functionality to read the external mesh +file. + +.. code:: python + + cells, boundary_points = domain.read_mesh( + i_mesh_file_name, + i_boundary_refinement_level, + i_boundary_sampling_method, + refinement_level=1, + ) + +`Return to top <#contents>`__ + +Setup fespace +^^^^^^^^^^^^^ + +Initialise the ``Fespace2D`` class with the required parameters. + +.. code:: python + + 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, + ) + +`Return to top <#contents>`__ + +Setup datahandler +^^^^^^^^^^^^^^^^^ + +Initialise the ``DataHandler`` class with the required parameters. + +.. code:: python + + datahandler = DataHandler2D(fespace, domain, dtype=i_dtype) + +`Return to top <#contents>`__ + +Setup model +^^^^^^^^^^^ + +Setup the necessary parameters for the model and initialise the ``Model`` +class. Before that fill the ``params`` dictionary with the required +parameters. + +.. code:: python + + model = DenseModel( + layer_dims=i_model_architecture, + 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, + ) + +`Return to top <#contents>`__ + +Pre-train setup +^^^^^^^^^^^^^^^ + +.. code:: python + + 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) + +Here the exact solution is being read from the external file. The +external solution at the test points is computed by FEM and stored in a +csv file. This sets up the test points and the exact solution. The +progress bar is initialised and the loss arrays are set up. The beta +value is set up as a constant tensor. `Return to top <#contents>`__ + +Training +^^^^^^^^ + +.. code:: python + + 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']) + +This ``train_step`` function trains the model for one epoch and returns +the loss. The loss is appended to the loss array. Then for every epoch +where +``(epoch + 1) % i_update_console_output == 0 or epoch == num_epochs - 1:`` + +.. code:: python + + 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}" + ) + +We will compute all the test errors and write the solution to a vtk file +for a complex mesh. Further, the console output will be printed with the +loss values and the test errors. `Return to top <#contents>`__ + +Post Training +^^^^^^^^^^^^^ + +.. code:: python + + # 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)) + +`Return to top <#contents>`__ + +This part of the code saves the model weights, writes the solution to a +vtk file, prints the error values in a table, prints the time values in +a table, and saves all the arrays as numpy arrays. + +save the outputs +---------------- + +All the outputs will be saved in the output directory specified in the +input file. The output directory will contain the following files: - +prediction_{epoch}.vtk : The solution file for each epoch. - +loss_function.txt : The loss function values for each epoch. - +prediction.txt : The predicted values at last epoch at the test points. +- exact.txt : The exact values at last epoch at the test points. - +error.txt : The error values at last epoch at the test points. - +time_per_epoch.txt : The time taken for each epoch. + +`Return to top <#contents>`__ + +Solution Plots +----------------- +.. image:: exact_solution.png + :alt: Exact Solution + :align: center + +.. image:: predicted_solution.png + :alt: Predicted Solution + :align: center + +.. image:: error.png + :alt: Error + :align: center + +References +------------- + +1. `FastVPINNs: Tensor-Driven Acceleration of VPINNs for Complex + Geometries. `__ + +`Return to top <#contents>`__ diff --git a/_sources/_rst/tutorials/forward_problems_2d/hard_boundary_constraints/poisson_2d/poisson2d_hard.rst.txt b/_sources/_rst/tutorials/forward_problems_2d/hard_boundary_constraints/poisson_2d/poisson2d_hard.rst.txt new file mode 100644 index 0000000..ee6d10e --- /dev/null +++ b/_sources/_rst/tutorials/forward_problems_2d/hard_boundary_constraints/poisson_2d/poisson2d_hard.rst.txt @@ -0,0 +1,415 @@ +Solving forward problems with FastVPINNs : Enforcing hard boundary constraints with an ansatz function. +======================================================================================================= + +In this example, we will learn how to use hard boundary constraints using FastVPINNs. +All the necessary files can be found in the examples folder of the `fastvpinns GitHub repository `_ + +.. math:: + + -\epsilon\Delta u(x) = f(x), \quad \ x \in \Omega = (-1, 1)^2 + +where + +.. math:: + + + f(x,y) = -2\omega^2\sin{\omega x}\sin{\omega y} + +We begin by introducing the various files required to run this example + +Contents +-------- + +- `Example File - sin_cos.py <#example-file>`__: + + - `Defining boundary values <#defining-boundary-values>`__ + - `Defining the forcing function <#defining-the-forcing-function>`__ + - `Defining bilinear parameters <#defining-bilinear-parameters>`__ + +- `Input File - Input.yaml <#input-file>`__: + + - `experimentation <#experimentation>`__ + - `geometry <#geometry>`__ + - `fe <#fe>`__ + - `pde <#pde>`__ + - `model <#model>`__ + - `logging <#logging>`__ + +- `Main File - main_poisson2d_hard.py <#main-file>`__: The main file is + used to run the experiment. + + - `Import relevant FastVPINNs + methods <#import-relevant-fastvpinns-methods>`__ + - `Reading the Input File <#reading-the-input-file>`__ + - `Setting up a Geometry2D object <#setting-up-a-geometry_2d-object>`__ + - `Reading the boundary conditions and + values <#reading-the-boundary-conditions-and-values>`__ + - `Setting up the finite element + space <#setting-up-the-finite-element-space>`__ + - `Defining the hard boundary constraint + ansatz <#defining-the-hard-boundary-constraint-ansatz>`__ + - `Instantiating a model with hard boundary + constraints <#instantiating-a-model-with-hard-boundary-constraints>`__ + +- `Training the model <#training-the-model>`__ + +The code in this example can be run using + +.. code:: bash + + python3 main_poisson2d_hard.py input.yaml + +Example File +------------ + +The example file, ``sin_cos.py``, defines the boundary conditions and +boundary values, the forcing function and exact function (if test error +needs to be calculated), bilinear parameters and the actual value of the +parameter that needs to be estimated (if the error between the actual +and estimated parameter needs to be calculated) + +Defining boundary +~~~~~~~~~~~~~~~~~ +values Since this example enforces zero Dirichlet boundary conditions +using hard constraints, the boundary functions defined in the example +file are not used. Instead, the ansatz function for hard boundary +constraints is defined in the `main file <#main-file>`__ + +.. figure:: rect.png + :alt: Unit Square + :align: center + +For internally generated geometries, the boundary id's will be hardcoded to +1000 for bottom, 1001 for right, 1002 for top, and 1003 for left; as shown in figure. + +Defining the forcing function +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +``rhs`` can be used to define the forcing function :math:`f`. + +.. code:: python + + 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 + +Defining bilinear parameters +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The bilinear parameters like diffusion constant can be defined by +``get_bilinear_params_dict`` + +.. code:: python + + def get_bilinear_params_dict(): + """ + This function will return a dictionary of bilinear parameters + """ + eps = 1.0 + + return {"eps": eps} + +Here, ``eps`` denoted the diffusion constant. + +`Back to Contents <#contents>`__ + +Input file +---------- + +The input file, ``input_inverse.yaml``, is used to define inputs to your +solver. These will usually parameters that will changed often throughout +your experimentation, hence it is best practice to pass these parameters +externally. The input file is divided based on the modules which use the +parameter in question, as follows - #``experimentation`` This +contains ``output_path``, a string which specifies which folder will be +used to store your outputs. + +geometry +~~~~~~~~~~~~ + +This section defines the geometrical parameters for your domain. 1. In +this example, we set the ``mesh_generation_method`` as ``"internal"``. +This generates a regular quadrilateral domain with a uniform mesh. 2. +The parameters in ``internal_mesh_params`` define the x and y limits of +the quadrilateral domain(\ ``xmin``, ``xmax``, ``ymin`` and ``ymax``), +number of cells in the domain in the x and y direction (``n_cells_x`` +and ``n_cells_y``), number of total boundary points +(``n_boundary_points``) and number of test points in x and y direction +(``n_test_points_x`` and ``n_test_points_y``). 3. ``mesh_type`` : +FastVPINNs currently provides support for quadrilateral elements only. +4. ``external_mesh_params`` can be used to specify parameters for the +external mesh, and can be ignored for this example + +fe +~~~~~~ + +The parameters related to the finite element space are defined here. 1. +``fe_order`` sets the order of the finite element test functions. 2. +``fe_type`` set which type of polynomial will be used as the finite +element test function. 3. ``quad_order`` is the number of quadrature in +each direction in each cell. Thus the total number of quadrature points +in each cell will be ``quad_order``\ :math:`^2` 4. ``quad_type`` +specifies the quadrature rule to be used. + +pde +~~~~~~~ + +``beta`` specifies the weight by which the boundary loss will be +multiplied before being added to the PDE loss. + +model +~~~~~~~~~ + +The parameters pertaining to the neural network are specified here. 1. +``model_architecture`` is used to specify the dimensions of the neural +network. In this example, [2, 30, 30, 30, 1] corresponds to a neural +network with 2 inputs (for a 2-dimensional problem), 1 output (for a +scalar problem) and 3 hidden layers with 30 neurons each. 2. +``activation`` specifies the activation function to be used. 3. +``use_attention`` specifies if attnention layers are to be used in the +model. This feature is currently under development and hence should be +set to ``false`` for now. 4. ``epochs`` is the number of iterations for +which the network must be trained. 5. ``dtype`` specifies which datatype +(``float32`` or ``float64``) will be used for the tensor calculations. +6. ``set_memory_growth``, when set to ``True`` will enable tensorflow’s +memory growth function, restricting the memory usage on the GPU. This is +currently under development and must be set to ``False`` for now. 7. +``learning_rate`` sets the learning rate ``initial_learning_rate`` if a +constant learning rate is used. A learning rate scheduler can be used by +toggling ``use_lr_scheduler`` to True and setting the corresponding +decay parameters below it. + +logging +~~~~~~~~~~~ + +It specifies the frequency with which the progress bar and console +output will be updated, and at what interval will inference be carried +out to print the solution image in the output folder. + +`Back to contents <#contents>`__ + +Main file +--------- + +This is the main file which needs to be run for the experiment, with the +input file as an argument. For the example, we will use the main file +``main_poisson2d_hard.py`` + +Following are the key components of a FastVPINNs main file + +Import relevant FastVPINNs methods +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. code:: python + + from fastvpinns.data.datahandler2d import DataHandler2D + from fastvpinns.FE.fespace2d import Fespace2D + from fastvpinns.Geometry.geometry_2d import Geometry_2D + +Will import the functions related to setting up the finite element +space, 2D Geometry and the datahandler required to manage data and make +it available to the model. + +.. code:: python + + from fastvpinns.model.model_hard import DenseModel_Hard + +Will import the model file where the neural network and its training +function is defined. The model file ``model_hard.py`` contains the +``DenseModel_Hard`` class. The ``call`` function in this model applies +the hard boundary constraint function to the output of the neural +network, and the ``train_step`` function does not add a supervised +boundary loss to the PDE residual for training. + +.. code:: python + + from fastvpinns.physics.poisson2d import pde_loss_poisson + +Imports the loss function for the 2-dimensional Poisson problem. + +.. code:: python + + from fastvpinns.utils.compute_utils import compute_errors_combined + from fastvpinns.utils.plot_utils import plot_contour, plot_loss_function, plot_test_loss_function + from fastvpinns.utils.print_utils import print_table + +Imports functions to calculate the loss, plot the results and print +outputs to the console. + +Reading the Input File +~~~~~~~~~~~~~~~~~~~~~~ + +The input file is loaded into ``config`` and the input parameters are +read and assigned to their respective variables. + +Setting up a ``Geometry_2D`` object +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. code:: python + + domain = Geometry_2D(i_mesh_type, i_mesh_generation_method, i_n_test_points_x, i_n_test_points_y, i_output_path) + +will instantiate a ``Geometry_2D`` object, ``domain``, with the mesh +type, mesh generation method and test points. In our example, the mesh +generation method is ``internal``, so the cells and boundary points will +be obtained using the ``generate_quad_mesh_internal`` method. + +.. code:: python + + 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, + ) + +Reading the boundary conditions and values +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +As explained in `the example file section <#example-file>`__, the +boundary conditions and values are read as a dictionary from the example +file + +.. code:: python + + bound_function_dict, bound_condition_dict = get_boundary_function_dict(), get_bound_cond_dict() + +Setting up the finite element space +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. code:: python + + 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, + ) + +``fespace`` will contain all the information about the finite element +space, including those read from the `input file <#input-file>`__ + +Defining the hard boundary constraint ansatz +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The ansatz function for applying zero Dirichlet hard boundary contraints +can be defined using ``apply_hard_boundary_constraints`` + +.. code:: python + + @tf.function + def apply_hard_boundary_constraints(inputs, x): + """This method applies hard boundary constraints to the model. + :param inputs: Input tensor + :type inputs: tf.Tensor + :param x: Output tensor from the model + :type x: tf.Tensor + :return: Output tensor with hard boundary constraints + :rtype: tf.Tensor + """ + ansatz = ( + tf.tanh(4.0 * np.pi * inputs[:, 0:1]) + * tf.tanh(4.0 * np.pi * inputs[:, 1:2]) + * tf.tanh(4.0 * np.pi * (inputs[:, 0:1] - 1.0)) + * tf.tanh(4.0 * np.pi * (inputs[:, 1:2] - 1.0)) + ) + ansatz = tf.cast(ansatz, i_dtype) + return ansatz * x + +Here, the ansatz we use is of the form +:math:`\tanh{(4\pi x)}\times\tanh{(4\pi(x-1))}\times\tanh{(4\pi y)}\times\tanh{(4\pi(y-1))}` + +Instantiating a model with hard boundary constraints +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. code:: python + + model = DenseModel_Hard( + 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, + hard_constraint_function=apply_hard_boundary_constraints, + ) + +``DenseModel_Hard`` is a model written for inverse problems with +spatially varying parameter estimation. In this problem, we pass the +loss function ``pde_loss_poisson`` from the ``physics`` file +``poisson2d.py``. + +Training the model +~~~~~~~~~~~~~~~~~~ + +We are now ready to train the model to approximate the solution of the +PDE. + +.. code:: python + + 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) + ... + +`Back to contents <#contents>`__ + +Solution +----------- +.. figure:: exact_solution.png + :alt: Exact Solution + :align: center + + Exact Solution + + +.. figure:: predicted_solution.png + :alt: Predicted Solution + :align: center + + Predicted Solution + + +.. figure:: error.png + :alt: Error + :align: center + + Error + + +References +------------- + +1. `FastVPINNs: Tensor-Driven Acceleration of VPINNs for Complex + Geometries. `__ diff --git a/_sources/_rst/tutorials/forward_problems_2d/uniform_mesh/helmholtz_2d/helmholtz2d_uniform.rst.txt b/_sources/_rst/tutorials/forward_problems_2d/uniform_mesh/helmholtz_2d/helmholtz2d_uniform.rst.txt new file mode 100644 index 0000000..3d6b3e5 --- /dev/null +++ b/_sources/_rst/tutorials/forward_problems_2d/uniform_mesh/helmholtz_2d/helmholtz2d_uniform.rst.txt @@ -0,0 +1,395 @@ +Solving forward problems with FastVPINNs : Helmholtz - 2D +========================================================= + +In this example, we will learn to solve the Helmholtz equation in 2D +All the necessary files can be found in the examples folder of the `fastvpinns GitHub repository `_ + +.. math:: + + -\epsilon\Delta u(x) + k^2 u = f(x), \quad \ x \in \Omega = (-1, 1)^2 + +where + +.. math:: + + + f(x,y) = 2 \pi cos(\pi y)sin(\pi x) + 2 \pi cos(\pi x) sin(\pi y) + (x+y) sin(\pi x) sin(\pi y) - \\ + 2 \pi^2 (x+y) sin(\pi x) sin(\pi y), + + +For this problem, the parameters are + +.. math:: + + + \epsilon = 1, + k = 1 + +The exact solution is given by + +.. math:: + + + u(x,y) = (x + y) sin(\pi x) sin(\pi y) + +We begin by introducing the various files required to run this example + +Contents +-------- + +- `Example File - helmholtz_example.py <#example-file>`__: + + - `Defining boundary values <#defining-boundary-values>`__ + - `Defining the forcing function <#defining-the-forcing-function>`__ + - `Defining bilinear parameters <#defining-bilinear-parameters>`__ + +- `Input File - input.yaml <#input-file>`__: + + - ```experimentation``` + - ```geometry``` + - ```fe``` + - ```pde``` + - ```model``` + - ```logging``` + +- `Main File - main_helmholtz.py <#main-file>`__: + + - `Import relevant FastVPINNs + methods <#import-relevant-fastvpinns-methods>`__ + - `Reading the Input File <#reading-the-input-file>`__ + - `Setting up a Geometry2D object <#setting-up-a-geometry_2d-object>`__ + - `Reading the boundary conditions and + values <#reading-the-boundary-conditions-and-values>`__ + - `Setting up the finite element + space <#setting-up-the-finite-element-space>`__ + - `Instantiating a model <#instantiating-a-model>`__ + - `Training the model <#training-the-model>`__ + +- `Solution <#solution>`__ + +The code in this example can be run using + +.. code:: bash + + python3 main_helmholtz_hard.py input.yaml + +Example File +------------ + +The example file, ``helmholtz_example.py``, defines the boundary +conditions and boundary values, the forcing function and exact function +(if test error needs to be calculated), bilinear parameters and the +actual value of the parameter that needs to be estimated (if the error +between the actual and estimated parameter needs to be calculated) + +Defining boundary values +~~~~~~~~~~~~~~~~~~~~~~~~ +Boundary values are defined using the functions ``get_boundary_function_dict`` and ``get_bound_cond_dict``. + +.. figure:: rect.png + :alt: Unit Square + :align: center + +For internally generated geometries, the boundary id's will be hardcoded to +1000 for bottom, 1001 for right, 1002 for top, and 1003 for left; as shown in figure. + +Defining the forcing function +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +``rhs`` can be used to define the forcing function :math:`f`. + +.. code:: python + + 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 + +Defining bilinear parameters +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The bilinear parameters like diffusion constant can be defined by +``get_bilinear_params_dict`` + +.. code:: python + + 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} + +Here, ``eps`` denoted the diffusion constant. + +`Back to Contents <#contents>`__ + +Input file +---------- + +The input file, ``input.yaml``, is used to define inputs to your solver. +These will usually parameters that will changed often throughout your +experimentation, hence it is best practice to pass these parameters +externally. The input file is divided based on the modules which use the +parameter in question, as follows - #``experimentation`` This +contains ``output_path``, a string which specifies which folder will be +used to store your outputs. + +``geometry`` +~~~~~~~~~~~~ + +This section defines the geometrical parameters for your domain. 1. In +this example, we set the ``mesh_generation_method`` as ``"internal"``. +This generates a regular quadrilateral domain with a uniform mesh. 2. +The parameters in ``internal_mesh_params`` define the x and y limits of +the quadrilateral domain(\ ``xmin``, ``xmax``, ``ymin`` and ``ymax``), +number of cells in the domain in the x and y direction (``n_cells_x`` +and ``n_cells_y``), number of total boundary points +(``n_boundary_points``) and number of test points in x and y direction +(``n_test_points_x`` and ``n_test_points_y``). 3. ``mesh_type`` : +FastVPINNs currently provides support for quadrilateral elements only. +4. ``external_mesh_params`` can be used to specify parameters for the +external mesh, and can be ignored for this example + +``fe`` +~~~~~~ + +The parameters related to the finite element space are defined here. 1. +``fe_order`` sets the order of the finite element test functions. 2. +``fe_type`` set which type of polynomial will be used as the finite +element test function. 3. ``quad_order`` is the number of quadrature in +each direction in each cell. Thus the total number of quadrature points +in each cell will be ``quad_order``\ :math:`^2` 4. ``quad_type`` +specifies the quadrature rule to be used. + +``pde`` +~~~~~~~ + +``beta`` specifies the weight by which the boundary loss will be +multiplied before being added to the PDE loss. + +``model`` +~~~~~~~~~ + +The parameters pertaining to the neural network are specified here. 1. +``model_architecture`` is used to specify the dimensions of the neural +network. In this example, [2, 30, 30, 30, 1] corresponds to a neural +network with 2 inputs (for a 2-dimensional problem), 1 output (for a +scalar problem) and 3 hidden layers with 30 neurons each. 2. +``activation`` specifies the activation function to be used. 3. +``use_attention`` specifies if attention layers are to be used in the +model. This feature is currently under development and hence should be +set to ``false`` for now. 4. ``epochs`` is the number of iterations for +which the network must be trained. 5. ``dtype`` specifies which datatype +(``float32`` or ``float64``) will be used for the tensor calculations. +6. ``set_memory_growth``, when set to ``True`` will enable tensorflow’s +memory growth function, restricting the memory usage on the GPU. This is +currently under development and must be set to ``False`` for now. 7. +``learning_rate`` sets the learning rate ``initial_learning_rate`` if a +constant learning rate is used. A learning rate scheduler can be used by +toggling ``use_lr_scheduler`` to True and setting the corresponding +decay parameters below it. + +``logging`` +~~~~~~~~~~~ + +It specifies the frequency with which the progress bar and console +output will be updated, and at what interval will inference be carried +out to print the solution image in the output folder. + +`Back to contents <#contents>`__ + +Main file +--------- + +This is the main file which needs to be run for the experiment, with the +input file as an argument. For the example, we will use the main file +``main_helmholtz.py`` + +Following are the key components of a FastVPINNs main file + +Import relevant FastVPINNs methods +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. code:: python + + from fastvpinns.data.datahandler2d import DataHandler2D + from fastvpinns.FE.fespace2d import Fespace2D + from fastvpinns.Geometry.geometry_2d import Geometry_2D + +Will import the functions related to setting up the finite element +space, 2D Geometry and the datahandler required to manage data and make +it available to the model. + +.. code:: python + + from fastvpinns.model.modelimport DenseModel + +Will import the model file where the neural network and its training +function is defined. The model file ``model.py`` contains the +``DenseModel`` class. the ``train_step`` function of this model is used +to train the model. + +.. code:: python + + from fastvpinns.physics.poisson2d import pde_loss_helmholtz + +Imports the loss function for the 2-dimensional Poisson problem. + +.. code:: python + + from fastvpinns.utils.compute_utils import compute_errors_combined + from fastvpinns.utils.plot_utils import plot_contour, plot_loss_function, plot_test_loss_function + from fastvpinns.utils.print_utils import print_table + +Imports functions to calculate the loss, plot the results and print +outputs to the console. + +Reading the Input File +~~~~~~~~~~~~~~~~~~~~~~ + +The input file is loaded into ``config`` and the input parameters are +read and assigned to their respective variables. + +Setting up a ``Geometry_2D`` object +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. code:: python + + domain = Geometry_2D(i_mesh_type, i_mesh_generation_method, i_n_test_points_x, i_n_test_points_y, i_output_path) + +will instantiate a ``Geometry_2D`` object, ``domain``, with the mesh +type, mesh generation method and test points. In our example, the mesh +generation method is ``internal``, so the cells and boundary points will +be obtained using the ``generate_quad_mesh_internal`` method. + +.. code:: python + + 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, + ) + +`Back to contents <#contents>`__ + +Reading the boundary conditions and values +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +As explained in `the example file section <#example-file>`__, the +boundary conditions and values are read as a dictionary from the example +file + +.. code:: python + + bound_function_dict, bound_condition_dict = get_boundary_function_dict(), get_bound_cond_dict() + +Setting up the finite element space +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. code:: python + + 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, + ) + +``fespace`` will contain all the information about the finite element +space, including those read from the `input file <#input-file>`__ + +`Back to contents <#contents>`__ + +Instantiating a model +~~~~~~~~~~~~~~~~~~~~~ + +.. code:: python + + 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, + ) + +In this problem, we pass the loss function ``pde_loss_helmholtz`` from +the ``physics`` file ``helmholtz2d``. + +We are now ready to train the model to approximate the solution of the +PDE. + +.. code:: python + + 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) + ... + +`Back to contents <#contents>`__ + +Solution +----------- +.. figure:: exact_solution.png + :alt: Exact Solution + :align: center + + Exact Solution + +.. figure:: predicted_solution.png + :alt: Predicted Solution + :align: center + + Predicted Solution + +.. figure:: error.png + :alt: Error + :align: center + + Error + + +`Back to contents <#contents>`__ + +References +------------- + +1. `FastVPINNs: Tensor-Driven Acceleration of VPINNs for Complex + Geometries. `__ diff --git a/_sources/_rst/tutorials/forward_problems_2d/uniform_mesh/poisson_2d/poisson2d_uniform.rst.txt b/_sources/_rst/tutorials/forward_problems_2d/uniform_mesh/poisson_2d/poisson2d_uniform.rst.txt new file mode 100644 index 0000000..1932c3c --- /dev/null +++ b/_sources/_rst/tutorials/forward_problems_2d/uniform_mesh/poisson_2d/poisson2d_uniform.rst.txt @@ -0,0 +1,379 @@ +Solving forward problems with FastVPINNs : Poisson - 2D +======================================================= + +In this example, we will learn how to solve a 2-dimensional Poisson problem using FastVPINNs. +All the necessary files can be found in the examples folder of the `fastvpinns GitHub repository `_ + +.. math:: + + -\epsilon\Delta u(x) = f(x), \quad \ x \in \Omega = (-1, 1)^2 + +where + +.. math:: + + + f(x,y) = -2\omega^2\sin{\omega x}\sin{\omega y} + +For an :math:`\epsilon = 1`, and considering :math:`\omega = 2 \pi` the +exact solution is given by + +.. math:: + + + u(x,y) = -\sin{2 \pi x}\sin{2 \pi y} + +We begin by introducing the various files required to run this example + +Contents +-------- + +- `Example File - sin_cos.py <#example-file>`__: + + - `Defining boundary values <#defining-boundary-values>`__ + - `Defining the forcing function <#defining-the-forcing-function>`__ + - `Defining bilinear parameters <#defining-bilinear-parameters>`__ + +- `Input File - input.yaml <#input-file>`__: + + - ```experimentation``` + - ```geometry``` + - ```fe``` + - ```pde``` + - ```model``` + - ```logging``` + +- `Main File - main_poisson2d.py <#main-file>`__: + + - `Import relevant FastVPINNs + methods <#import-relevant-fastvpinns-methods>`__ + - `Reading the Input File <#reading-the-input-file>`__ + - `Setting up a Geometry2D object <#setting-up-a-geometry_2d-object>`__ + - `Reading the boundary conditions and + values <#reading-the-boundary-conditions-and-values>`__ + - `Setting up the finite element + space <#setting-up-the-finite-element-space>`__ + - `Instantiating a model <#instantiating-a-model>`__ + - `Training the model <#training-the-model>`__ + +- `Solution <#solution>`__ + +The code in this example can be run using + +.. code:: bash + + python3 main_poisson2d_hard.py input.yaml + +Example File +------------ + +The example file, ``sin_cos.py``, defines the boundary conditions and +boundary values, the forcing function and exact function (if test error +needs to be calculated), bilinear parameters and the actual value of the +parameter that needs to be estimated (if the error between the actual +and estimated parameter needs to be calculated) + +Defining boundary values +~~~~~~~~~~~~~~~~~~~~~~~~ +Boundary values are defined using the functions ``get_boundary_function_dict`` and ``get_bound_cond_dict``. + +.. figure:: rect.png + :alt: Unit Square + :align: center + +For internally generated geometries, the boundary id's will be hardcoded to +1000 for bottom, 1001 for right, 1002 for top, and 1003 for left; as shown in figure. + +Defining the forcing function +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +``rhs`` can be used to define the forcing function :math:`f`. + +.. code:: python + + 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 + +Defining bilinear parameters +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The bilinear parameters like diffusion constant can be defined by +``get_bilinear_params_dict`` + +.. code:: python + + def get_bilinear_params_dict(): + """ + This function will return a dictionary of bilinear parameters + """ + eps = 1.0 + + return {"eps": eps} + +Here, ``eps`` denoted the diffusion constant. + +`Back to Contents <#contents>`__ + +Input file +---------- + +The input file, ``input.yaml``, is used to define inputs to your solver. +These will usually parameters that will changed often throughout your +experimentation, hence it is best practice to pass these parameters +externally. The input file is divided based on the modules which use the +parameter in question, as follows - ``experimentation`` This +contains ``output_path``, a string which specifies which folder will be +used to store your outputs. + +``geometry`` +~~~~~~~~~~~~ + +This section defines the geometrical parameters for your domain. 1. In +this example, we set the ``mesh_generation_method`` as ``"internal"``. +This generates a regular quadrilateral domain with a uniform mesh. 2. +The parameters in ``internal_mesh_params`` define the x and y limits of +the quadrilateral domain(\ ``xmin``, ``xmax``, ``ymin`` and ``ymax``), +number of cells in the domain in the x and y direction (``n_cells_x`` +and ``n_cells_y``), number of total boundary points +(``n_boundary_points``) and number of test points in x and y direction +(``n_test_points_x`` and ``n_test_points_y``). 3. ``mesh_type`` : +FastVPINNs currently provides support for quadrilateral elements only. +4. ``external_mesh_params`` can be used to specify parameters for the +external mesh, and can be ignored for this example + +``fe`` +~~~~~~ + +The parameters related to the finite element space are defined here. 1. +``fe_order`` sets the order of the finite element test functions. 2. +``fe_type`` set which type of polynomial will be used as the finite +element test function. 3. ``quad_order`` is the number of quadrature in +each direction in each cell. Thus the total number of quadrature points +in each cell will be ``quad_order``\ :math:`^2` 4. ``quad_type`` +specifies the quadrature rule to be used. + +``pde`` +~~~~~~~ + +``beta`` specifies the weight by which the boundary loss will be +multiplied before being added to the PDE loss. + +``model`` +~~~~~~~~~ + +The parameters pertaining to the neural network are specified here. 1. +``model_architecture`` is used to specify the dimensions of the neural +network. In this example, [2, 30, 30, 30, 1] corresponds to a neural +network with 2 inputs (for a 2-dimensional problem), 1 output (for a +scalar problem) and 3 hidden layers with 30 neurons each. 2. +``activation`` specifies the activation function to be used. 3. +``use_attention`` specifies if attention layers are to be used in the +model. This feature is currently under development and hence should be +set to ``false`` for now. 4. ``epochs`` is the number of iterations for +which the network must be trained. 5. ``dtype`` specifies which datatype +(``float32`` or ``float64``) will be used for the tensor calculations. +6. ``set_memory_growth``, when set to ``True`` will enable tensorflow’s +memory growth function, restricting the memory usage on the GPU. This is +currently under development and must be set to ``False`` for now. 7. +``learning_rate`` sets the learning rate ``initial_learning_rate`` if a +constant learning rate is used. A learning rate scheduler can be used by +toggling ``use_lr_scheduler`` to True and setting the corresponding +decay parameters below it. + +``logging`` +~~~~~~~~~~~ + +It specifies the frequency with which the progress bar and console +output will be updated, and at what interval will inference be carried +out to print the solution image in the output folder. + +`Back to contents <#contents>`__ + +Main file +--------- + +This is the main file which needs to be run for the experiment, with the +input file as an argument. For the example, we will use the main file +``main_poisson2d.py`` + +Following are the key components of a FastVPINNs main file + +Import relevant FastVPINNs methods +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. code:: python + + from fastvpinns.data.datahandler2d import DataHandler2D + from fastvpinns.FE.fespace2d import Fespace2D + from fastvpinns.Geometry.geometry_2d import Geometry_2D + +Will import the functions related to setting up the finite element +space, 2D Geometry and the datahandler required to manage data and make +it available to the model. + +.. code:: python + + from fastvpinns.model.modelimport DenseModel + +Will import the model file where the neural network and its training +function is defined. The model file ``model.py`` contains the +``DenseModel`` class. the ``train_step`` function of this model is used +to train the model. + +.. code:: python + + from fastvpinns.physics.poisson2d import pde_loss_poisson + +Imports the loss function for the 2-dimensional Poisson problem. + +.. code:: python + + from fastvpinns.utils.compute_utils import compute_errors_combined + from fastvpinns.utils.plot_utils import plot_contour, plot_loss_function, plot_test_loss_function + from fastvpinns.utils.print_utils import print_table + +Imports functions to calculate the loss, plot the results and print +outputs to the console. + +Reading the Input File +~~~~~~~~~~~~~~~~~~~~~~ + +The input file is loaded into ``config`` and the input parameters are +read and assigned to their respective variables. + +Setting up a ``Geometry_2D`` object +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. code:: python + + domain = Geometry_2D(i_mesh_type, i_mesh_generation_method, i_n_test_points_x, i_n_test_points_y, i_output_path) + +will instantiate a ``Geometry_2D`` object, ``domain``, with the mesh +type, mesh generation method and test points. In our example, the mesh +generation method is ``internal``, so the cells and boundary points will +be obtained using the ``generate_quad_mesh_internal`` method. + +.. code:: python + + 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, + ) + +`Back to contents <#contents>`__ + +Reading the boundary conditions and values +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +As explained in `the example file section <#example-file>`__, the +boundary conditions and values are read as a dictionary from the example +file + +.. code:: python + + bound_function_dict, bound_condition_dict = get_boundary_function_dict(), get_bound_cond_dict() + +Setting up the finite element space +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. code:: python + + 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, + ) + +``fespace`` will contain all the information about the finite element +space, including those read from the `input file <#input-file>`__ + +`Back to contents <#contents>`__ + +Instantiating a model +~~~~~~~~~~~~~~~~~~~~~ + +.. code:: python + + 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, + ) + +In this problem, we pass the loss function ``pde_loss_poisson`` from the +``physics`` file ``poisson2d.py``. + +We are now ready to train the model to approximate the solution of the +PDE. + +.. code:: python + + 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) + ... + +`Back to contents <#contents>`__ + +Solution +-------- +.. image:: exact_solution.png + :alt: Exact Solution + :align: center + + +.. image:: predicted_solution.png + :alt: Predicted Solution + :align: center + + +.. image:: error.png + :alt: Error + :align: center + + +`Back to contents <#contents>`__ + +References +---------- + +1. `FastVPINNs: Tensor-Driven Acceleration of VPINNs for Complex + Geometries. `__ diff --git a/_sources/_rst/tutorials/inverse_problems_2d/const_inverse_poisson2d/inverse_constant.rst.txt b/_sources/_rst/tutorials/inverse_problems_2d/const_inverse_poisson2d/inverse_constant.rst.txt new file mode 100644 index 0000000..ee8ab18 --- /dev/null +++ b/_sources/_rst/tutorials/inverse_problems_2d/const_inverse_poisson2d/inverse_constant.rst.txt @@ -0,0 +1,454 @@ +Solving Inverse Problems with FastVPINNs : Estimation of uniform diffusion parameter on a quadrilateral geometry. +================================================================================================================= + +In this example, we will learn how to solve inverse problems using +FastVPINNs. In particular, we will solve the 2-dimensional Poisson +equation, as shown below, while simultaneously estimating the uniform +diffusion parameter :math:`\epsilon` using synthetically generated +sensor data. + +.. math:: + + -\epsilon\Delta u(x) = f(x), \quad \ x \in \Omega = (-1, 1)^2 + +for the actual solution +:math:`u(x, y) = 10 \sin(x) \tanh(x) e^{-\epsilon x^2}` In this problem, +the actual value of the diffusion parameter, +:math:`\epsilon_{\text{actual}}` is 0.3, and we start with an initial +guess of :math:`\epsilon_{\text{initial}}=2.0`. + +We begin by introducing the various files required to run this example + +Contents +-------- + +- `Example File - inverse_uniform.py <#example-file>`__: The boundary + conditions, forcing function :math:`f` and parameters are defined in + this file. +- `Input File - input_inverse.py <#input_file>`__: The input file + contains parameters for the finite element space and neural networks + that can be tuned. +- `Main File - main_inverse.py <#main-file>`__: The main file is the + file that is actually run. + +The code in this example can be run using + +.. code:: bash + + python3 main_inverse.py input_inverse.yaml + +Example File +------------ + +The example file, ``inverse_uniform.py``, defines the boundary +conditions and boundary values, the forcing function and exact function +(if test error needs to be calculated), bilinear parameters and the +actual value of the parameter that needs to be estimated (if the error +between the actual and estimated parameter needs to be calculated) ### +Defining boundary values The current version of FastVPINNs only +implements Dirichlet boundary conditions. The boundary values can be set +by defining a function for each boundary, + +.. code:: python + + EPS = 0.3 + + + def left_boundary(x, y): + """ + This function will return the boundary value for given component of a boundary + """ + val = np.sin(x) * np.tanh(x) * np.exp(-1.0 * EPS * (x**2)) * 10 + return val + +Here ``EPS`` is the actual value of the diffusion parameter to be +estimated. In the above snippet, we define a function ``left_boundary`` +which returns the Dirichlet values to be enforced at that boundary. +Similarly, we can define more boundary functions like +``right_boundary``, ``top_boundary`` and ``bottom_boundary``. Once these +functions are defined, we can assign them to the respective boundaries +using ``get_boundary_function_dict`` + +.. figure:: rect.png + :alt: Unit Square + :align: center + +.. code:: python + + 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} + +Here, ``1000``, ``1001``, etc. are the boundary identifiers obtained +from the geometry. Thus, each boundary gets mapped to it boundary value +in the dictionary. + +Defining boundary conditions +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +As explained above, each boundary has an identifier. The function +``get_bound_cond_dict`` maps the boundary identifier to the boundary +condition (only Dirichlet boundary condition is implemented at this +point). + +.. code:: python + + def get_bound_cond_dict(): + """ + This function will return a dictionary of boundary conditions + """ + return {1000: "dirichlet", 1001: "dirichlet", 1002: "dirichlet", 1003: "dirichlet"} + +Defining the forcing function +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +``rhs`` can be used to define the forcing function :math:`f`. + +.. code:: python + + def rhs(x, y): + """ + This function will return the value of the rhs at a given point + """ + + X = x + Y = y + eps = EPS + + return ( + -EPS + * ( + 40.0 * X * eps * (np.tanh(X) ** 2 - 1) * np.sin(X) + - 40.0 * X * eps * np.cos(X) * np.tanh(X) + + 10 * eps * (4.0 * X**2 * eps - 2.0) * np.sin(X) * np.tanh(X) + + 20 * (np.tanh(X) ** 2 - 1) * np.sin(X) * np.tanh(X) + - 20 * (np.tanh(X) ** 2 - 1) * np.cos(X) + - 10 * np.sin(X) * np.tanh(X) + ) + * np.exp(-1.0 * X**2 * eps) + ) + +Defining bilinear parameters +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The bilinear parameters like diffusion constant and convective velocity +can be defined by ``get_bilinear_params_dict`` + +.. code:: python + + def get_bilinear_params_dict(): + """ + This function will return a dictionary of bilinear parameters + """ + # Initial Guess + eps = EPS + + return {"eps": eps} + +Here, ``eps`` denoted the diffusion constant. + +Defining the target parameter values for testing +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +To test if our solver converges to the correct value of the parameter to +be estimated, we use the function ``get_inverse_params_actual_dict``. + +.. code:: python + + def get_inverse_params_actual_dict(): + """ + This function will return a dictionary of inverse parameters + """ + # Initial Guess + eps = EPS + + return {"eps": eps} + +This can then be used to calculate some error metric that assesses the +performance of our solver. + +`Back to Contents <#contents>`__ + +Input file +---------- + +The input file, ``input_inverse.yaml``, is used to define inputs to your +solver. These will usually parameters that will changed often throughout +your experimentation, hence it is best practice to pass these parameters +externally. The input file is divided based on the modules which use the +parameter in question, as follows - ### ``experimentation`` This +contains ``output_path``, a string which specifies which folder will be +used to store your outputs. + +``geometry`` +~~~~~~~~~~~~ + +This section defines the geometrical parameters for your domain. 1. In +this example, we set the ``mesh_generation_method`` as ``"internal"``. +This generates a regular quadrilateral domain with a uniform mesh. 2. +The parameters in ``internal_mesh_params`` define the x and y limits of +the quadrilateral domain(\ ``xmin``, ``xmax``, ``ymin`` and ``ymax``), +number of cells in the domain in the x and y direction (``n_cells_x`` +and ``n_cells_y``), number of total boundary points +(``n_boundary_points``) and number of test points in x and y direction +(``n_test_points_x`` and ``n_test_points_y``). 3. ``mesh_type`` : +FastVPINNs currently provides support for quadrilateral elements only. +4. ``external_mesh_params`` can be used to specify parameters for the +external mesh, and can be ignored for this example + +``fe`` +~~~~~~ + +The parameters related to the finite element space are defined here. +1. ``fe_order`` sets the order of the finite element test functions. + +2. ``fe_type`` set which type of polynomial will be used as the finite +element test function. + +3. ``quad_order`` is the number of quadrature in +each direction in each cell. Thus the total number of quadrature points +in each cell will be ``quad_order``\ :math:`^2` + +4. ``quad_type`` specifies the quadrature rule to be used. + +``pde`` +~~~~~~~ + +``beta`` specifies the weight by which the boundary loss will be +multiplied before being added to the PDE loss. + +``model`` +~~~~~~~~~ + +The parameters pertaining to the neural network are specified here. 1. +``model_architecture`` is used to specify the dimensions of the neural +network. In this example, [2, 30, 30, 30, 1] corresponds to a neural +network with 2 inputs (for a 2-dimensional problem), 1 output (for a +scalar problem) and 3 hidden layers with 30 neurons each. 2. +``activation`` specifies the activation function to be used. 3. +``use_attention`` specifies if attnention layers are to be used in the +model. This feature is currently under development and hence should be +set to ``false`` for now. 4. ``epochs`` is the number of iterations for +which the network must be trained. 5. ``dtype`` specifies which datatype +(``float32`` or ``float64``) will be used for the tensor calculations. +6. ``set_memory_growth``, when set to ``True`` will enable tensorflow’s +memory growth function, restricting the memory usage on the GPU. This is +currently under development and must be set to ``False`` for now. 7. +``learning_rate`` sets the learning rate ``initial_learning_rate`` if a +constant learning rate is used. A learning rate scheduler can be used by +toggling ``use_lr_scheduler`` to True and setting the corresponding +decay parameters below it. + +``logging`` +~~~~~~~~~~~ + +It specifies the frequency with which the progress bar and console +output will be updated, and at what interval will inference be carried +out to print the solution image in the output folder. + +``inverse`` +~~~~~~~~~~~ + +Specific inputs only for inverse problems. ``num_sensor_points`` +specifies the number of points in the domain at which the solution is +known (or “sensed”). + +`Back to contents <#contents>`__ + +Main file +--------- + +This is the main file which needs to be run for the experiment, with the +input file as an argument. For the example, we will use the main file +``main_inverse.py`` + +Following are the key components of a FastVPINNs main file + +Import relevant FastVPINNs methods +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. code:: python + + from fastvpinns.data.datahandler2d import DataHandler2D + from fastvpinns.FE.fespace2d import Fespace2D + from fastvpinns.Geometry.geometry_2d import Geometry_2D + +Will import the functions related to setting up the finite element +space, 2D Geometry and the datahandler required to manage data and make +it available to the model. + +.. code:: python + + from fastvpinns.model.model_inverse import DenseModel_Inverse + +Will import the model file where the neural network and its training +function is defined. The model file ``model_inverse.py`` contains the +``DenseModel_Inverse`` class specifically designed for inverse problems +where a spatially varying parameter has to be estimated along with the +solution. + +.. code:: python + + from fastvpinns.physics.poisson2d_inverse import * + +Imports the loss function specifically designed for this problem, with a +sensor loss added to the PDE and boundary losses. + +.. code:: python + + from fastvpinns.utils.compute_utils import compute_errors_combined + from fastvpinns.utils.plot_utils import plot_contour, plot_loss_function, plot_test_loss_function + from fastvpinns.utils.print_utils import print_table + +Imports functions to calculate the loss, plot the results and print +outputs to the console. + +Reading the Input File +~~~~~~~~~~~~~~~~~~~~~~ + +The input file is loaded into ``config`` and the input parameters are +read and assigned to their respective variables. + +Setting up a ``Geometry_2D`` object +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. code:: python + + domain = Geometry_2D(i_mesh_type, i_mesh_generation_method, i_n_test_points_x, i_n_test_points_y, i_output_path) + +will instantiate a ``Geometry_2D`` object, ``domain``, with the mesh +type, mesh generation method and test points. In our example, the mesh +generation method is ``internal``, so the cells and boundary points will +be obtained using the ``generate_quad_mesh_internal`` method. + +.. code:: python + + 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, + ) + +Reading the boundary conditions and values +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +As explained in `the example file section <#example-file>`__, the +boundary conditions and values are read as a dictionary from the example +file + +.. code:: python + + bound_function_dict, bound_condition_dict = get_boundary_function_dict(), get_bound_cond_dict() + +Setting up the finite element space +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. code:: python + + 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, + ) + +``fespace`` will contain all the information about the finite element +space, including those read from the `input file <#input-file>`__ + +Instantiating an inverse problem model +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. code:: python + + model = DenseModel_Inverse( + layer_dims=i_model_architecture, + learning_rate_dict=i_learning_rate_dict, + params_dict=params_dict, + loss_function=pde_loss_poisson_inverse, + 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, + sensor_list=[points, sensor_values], + inverse_params_dict=inverse_params_dict, + tensor_dtype=i_dtype, + use_attention=i_use_attention, + activation=i_activation, + hessian=False, + ) + +``DenseModel_Inverse`` is a model written for inverse problems with +spatially varying parameter estimation. In this problem, we pass the +loss function ``pde_loss_poisson_inverse`` from the ``physics`` file +``poisson_inverse.py``. + +We are now ready to train the model to approximate the solution of the +PDE while estimating the unknown diffusion parameter using the sensor +data. + +.. code:: python + + 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) + ... + +`Back to contents <#contents>`__ + +Solution +----------- + + .. figure:: exact_solution.png + :alt: Exact Solution + :align: center + + Exact Solution + + .. figure:: predicted_solution.png + :alt: Predicted Solution + :align: center + + Predicted Solution + + .. figure:: error.png + :alt: Error + :align: center + + Error + + .. figure:: inverse_eps_prediction.png + :alt: inverse_eps_prediction + :align: center + + inverse_eps_prediction + + .. figure:: loss_function.png + :alt: Train Loss + :align: center + + Train Loss + +References +----------- + +1. `FastVPINNs: Tensor-Driven Acceleration of VPINNs for Complex + Geometries. `__ diff --git a/_sources/_rst/tutorials/inverse_problems_2d/domain_inverse_cd2d/domain_inverse.rst.txt b/_sources/_rst/tutorials/inverse_problems_2d/domain_inverse_cd2d/domain_inverse.rst.txt new file mode 100644 index 0000000..4671e84 --- /dev/null +++ b/_sources/_rst/tutorials/inverse_problems_2d/domain_inverse_cd2d/domain_inverse.rst.txt @@ -0,0 +1,447 @@ +Solving Inverse Problems with FastVPINNs : Estimation of spatially varying parameter on a complex geometry. +=========================================================================================================== + +In this example, we will learn how to solve inverse problems on a +complex geometry using FastVPINNs. In particular, we will solve the +2-dimensional convection-diffusion equation, as shown below, while +simultaneously estimating the spatially dependent diffusion parameter +:math:`\epsilon(x,y)` using synthetically generated sensor data. + +.. math:: -\left(\frac{\partial}{\partial x}\left(\epsilon(x,y)\frac{\partial u}{\partial x}\right) + \frac{\partial}{\partial y}\left(\epsilon(x,y)\frac{\partial u}{\partial y}\right)\right) + b_x\frac{\partial u}{\partial x} + b_y\frac{\partial u}{\partial y} = f + +where + +.. math:: f=10; \quad \epsilon_{\text{actual}}=0.5\times(\sin{x} + \cos{y}); \qquad b_x=1.0; \quad b_y=0.0 + +We begin by introducing the various files required to run this example + +Computational Domain +^^^^^^^^^^^^^^^^^^^^ + +The computational domain is a circular domain with radius 1 centered at +(0, 0). + +.. figure:: mesh.png + :alt: alt text + +Contents +-------- + +- `Example File <#example-file>`__: The boundary conditions, forcing + function :math:`f` and parameters are defined in this file. +- `Input File <#input_file>`__: The input file contains parameters for + the finite element space and neural networks that can be tuned. +- `Main File <#main-file>`__: The main file is the file that is + actually run. + +The code in this example can be run using + +.. code:: bash + + python3 main_inverse_domain_circle.py input_inverse_domain.yaml + +Example File +------------ + +The example file, ``cd2d_inverse_circle_example.py``, defines the +boundary conditions and boundary values, the forcing function and exact +function (if test error needs to be calculated), bilinear parameters and +the actual value of the parameter that needs to be estimated (if the +error between the actual and estimated parameter needs to be calculated) + + +Defining boundary values +------------------------ + +The current version of FastVPINNs only +implements Dirichlet boundary conditions. The boundary values can be set +by defining a function for each boundary, + +.. code:: python + + def circle_boundary(x, y): + """ + This function will return the boundary value for given component of a boundary + """ + val = np.ones_like(x) * 0.0 + return val + +The function ``circle_boundary`` returns the boundary value for a given +component of the boundary. The function ``get_boundary_function_dict`` +returns a dictionary of boundary functions. The key of the dictionary is +the boundary id and the value is the boundary function. The function +``get_bound_cond_dict`` returns a dictionary of boundary conditions. The +key of the dictionary is the boundary id and the value is the boundary +condition. + +.. code:: python + + def get_boundary_function_dict(): + """ + This function will return a dictionary of boundary functions + """ + return {1000: circle_boundary} + +For externally created geometries from gmsh, the user needs to provide +the physical tag for the boundaries present in the geometry. +In our case, we have used 1000 to define the circular boundary in mesh file. + +.. figure:: unitcircle.png + :alt: Unit Circle + :align: center + +Defining boundary conditions +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +As explained above, each boundary has an identifier. The function +``get_bound_cond_dict`` maps the boundary identifier to the boundary +condition (only Dirichlet boundary condition is implemented at this +point). + +.. code:: python + + def get_bound_cond_dict(): + """ + This function will return a dictionary of boundary conditions + """ + return {1000: circle_boundary} + +Defining the forcing function +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +``rhs`` can be used to define the forcing function :math:`f`. + +.. code:: python + + def rhs(x, y): + """ + This function will return the value of the rhs at a given point + """ + return 10.0 * np.ones_like(x) + +Defining bilinear parameters +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The bilinear parameters like diffusion constant and convective velocity +can be defined by ``get_bilinear_params_dict`` + +.. code:: python + + def get_bilinear_params_dict(): + """ + This function will return a dictionary of bilinear parameters + """ + + eps = 0.1 # will not be used in the loss function, as it will be replaced by the predicted value of NN + b1 = 1 + b2 = 0 + c = 0.0 + + return {"eps": eps, "b_x": b1, "b_y": b2, "c": c} + +Here, ``eps`` denoted the diffusion constant, ``b_x`` and ``b_y`` denote +the convective velocity in x and y direction respectively, and ``c`` +denotes the reaction term. In this particular example, ``eps`` is not +used in the loss calculation since it is the parameter to be estimated +and ``c`` is zero since this is simply a convection-diffusion problem. + +Defining the target parameter values for testing +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +To test if our solver converges to the correct value of the parameter to +be estimated, we use the function ``get_inverse_params_actual_dict``. + +.. code:: python + + def get_inverse_params_actual_dict(x, y): + """ + This function will return a dictionary of inverse parameters + """ + # Initial Guess + eps = 0.5 * (np.sin(x) + np.cos(y)) + return {"eps": eps} + +This can then be used to calculate some error metric that assesses the +performance of our solver. + +`Back to Contents <#contents>`__ + +Input file +---------- + +The input file, ``input_inverse_domain.yaml``, is used to define inputs +to your solver. These will usually parameters that will changed often +throughout your experimentation, hence it is best practice to pass these +parameters externally. The input file is divided based on the modules +which use the parameter in question, as follows - ### +``experimentation`` This contains ``output_path``, a string which +specifies which folder will be used to store your outputs. + +``geometry`` +~~~~~~~~~~~~ + +This section defines the geometrical parameters for your domain. 1. In +this example, we set the ``mesh_generation_method`` as ``"external"`` +since we want to read the mesh file for the circular domain, +``circular_quad.mesh``. 2. For the purposes of this example, the +parameters in ``internal_mesh_params`` can be ignored as they are used +exclusively for internal meshes. 3. ``mesh_type`` : FastVPINNs currently +provides support for quadrilateral elements only. 4. +``external_mesh_params`` can be used to specify parameters for the +external mesh. ``mesh_file_name`` takes a string (``circular_quad_mesh`` +in this case). ``boundary_refinement_level`` controls how many times the +boundaries are refined and in effect decides the number of boundary +points sampled. This sampling can be set to ``uniform`` for uniform +sampling. + +``fe`` +~~~~~~ + +The parameters related to the finite element space are defined here. 1. +``fe_order`` sets the order of the finite element test functions. 2. +``fe_type`` set which type of polynomial will be used as the finite +element test function. 3. ``quad_order`` is the number of quadrature in +each direction in each cell. Thus the total number of quadrature points +in each cell will be ``quad_order``\ :math:`^2` 4. ``quad_type`` +specifies the quadrature rule to be used. + +``pde`` +~~~~~~~ + +``beta`` specifies the weight by which the boundary loss will be +multiplied before being added to the PDE loss. + +``model`` +~~~~~~~~~ + +The parameters pertaining to the neural network are specified here. 1. +``model_architecture`` is used to specify the dimensions of the neural +network. In this example, [2, 30, 30, 30, 1] corresponds to a neural +network with 2 inputs (for a 2-dimensional problem), 1 output (for a +scalar problem) and 3 hidden layers with 30 neurons each. 2. +``activation`` specifies the activation function to be used. 3. +``use_attention`` specifies if attnention layers are to be used in the +model. This feature is currently under development and hence should be +set to ``false`` for now. 4. ``epochs`` is the number of iterations for +which the network must be trained. 5. ``dtype`` specifies which datatype +(``float32`` or ``float64``) will be used for the tensor calculations. +6. ``set_memory_growth``, when set to ``True`` will enable tensorflow’s +memory growth function, restricting the memory usage on the GPU. This is +currently under development and must be set to ``False`` for now. 7. +``learning_rate`` sets the learning rate ``initial_learning_rate`` if a +constant learning rate is used. A learning rate scheduler can be used by +toggling ``use_lr_scheduler`` to True and setting the corresponding +decay parameters below it. + +``logging`` +~~~~~~~~~~~ + +It specifies the frequency with which the progress bar and console +output will be updated, and at what interval will inference be carried +out to print the solution image in the output folder. + +``inverse`` +~~~~~~~~~~~ + +Specific inputs only for inverse problems. ``num_sensor_points`` +specifies the number of points in the domain at which the solution is +known (or “sensed”). This sensor data can be synthetic or be read from a +file given by ``sensor_data_file``. + +`Back to contents <#contents>`__ + +Main file +--------- + +This is the main file which needs to be run for the experiment, with the +input file as an argument. For the example, we will use the main file +``main_inverse_domain_circle.py`` + +Following are the key components of a FastVPINNs main file + +Import relevant FastVPINNs methods +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. code:: python + + from fastvpinns.data.datahandler2d import DataHandler2D + from fastvpinns.FE.fespace2d import Fespace2D + from fastvpinns.Geometry.geometry_2d import Geometry_2D + +Will import the functions related to setting up the finite element +space, 2D Geometry and the datahandler required to manage data and make +it available to the model. + +.. code:: python + + from fastvpinns.model.model_inverse_domain import DenseModel_Inverse_Domain + +Will import the model file where the neural network and its training +function is defined. The model file ``model_inverse_domain.py`` contains +the ``DenseModel_Inverse_Domain`` class specifically designed for +inverse problems where a spatially varying parameter has to be estimated +along with the solution. + +.. code:: python + + from fastvpinns.physics.cd2d_inverse_domain import * + +Imports the loss function specifically designed for this problem, with a +sensor loss added to the PDE and boundary losses. + +.. code:: python + + from fastvpinns.utils.compute_utils import compute_errors_combined + from fastvpinns.utils.plot_utils import plot_contour, plot_loss_function, plot_test_loss_function + from fastvpinns.utils.print_utils import print_table + +Imports functions to calculate the loss, plot the results and print +outputs to the console. + +Reading the Input File +~~~~~~~~~~~~~~~~~~~~~~ + +The input file is loaded into ``config`` and the input parameters are +read and assigned to their respective variables. + +Setting up a ``Geometry_2D`` object +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. code:: python + + domain = Geometry_2D(i_mesh_type, i_mesh_generation_method, i_n_test_points_x, i_n_test_points_y, i_output_path) + +will instantiate a ``Geometry_2D`` object, ``domain``, with the mesh +type, mesh generation method and test points. In our example, the mesh +generation method is ``external``, so the cells and boundary points will +be obtained using the ``read_mesh`` method. + +.. code:: python + + cells, boundary_points = domain.read_mesh(mesh_file=i_mesh_file_name, boundary_point_refinement_level=i_boundary_refinement_level, + bd_sampling_method=i_boundary_sampling_method, + refinement_level=0) + +Reading the boundary conditions and values +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +As explained in `the example file section <#example-file>`__, the +boundary conditions and values are read as a dictionary from the example +file + +.. code:: python + + bound_function_dict, bound_condition_dict = get_boundary_function_dict(), get_bound_cond_dict() + +Setting up the finite element space +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. code:: python + + 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, + ) + +| ``fespace`` will contain all the information about the finite element + space, including those read from the `input file <#input-file>`__ +| #Instantiating an inverse problem model + +.. code:: python + + model = DenseModel_Inverse_Domain( + layer_dims=i_model_architecture, + learning_rate_dict=i_learning_rate_dict, + params_dict=params_dict, + loss_function=pde_loss_cd2d_inverse_domain, + 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, + sensor_list=[points, sensor_values], + tensor_dtype=i_dtype, + use_attention=i_use_attention, + activation=i_activation, + hessian=False, + ) + +``DenseModel_Inverse_Domain`` is a model written for inverse problems +with spatially varying parameter estimation. In this problem, we pass +the loss function ``pde_loss_cd2d_inverse_domain`` from the ``physics`` +file ``cd2d_inverse_domain.py``. + +We are now ready to train the model to approximate the solution of the +PDE while estimating the unknown diffusion parameter using the sensor +data. + +.. code:: python + + 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) + ... + +Solution +----------- +.. figure:: exact_solution.png + :alt: Exact Solution + :align: center + + Exact Solution + +.. figure:: predicted_solution.png + :alt: Predicted Solution + :align: center + + Predicted Solution + +.. figure:: error.png + :alt: Error + :align: center + + Error + +.. figure:: epsilon_exact.png + :alt: Epsilon Exact + :align: center + + Epsilon Exact + +.. figure:: epsilon_predicted.png + :alt: Epsilon Predicted + :align: center + + Epsilon Predicted + +.. figure:: epsilon_error.png + :alt: Epsilon Error + :align: center + + Epsilon Error + +`Back to contents <#contents>`__ + +References +------------- + +1. `FastVPINNs: Tensor-Driven Acceleration of VPINNs for Complex + Geometries. `__ + +`Back to contents <#contents>`__ diff --git a/_sources/index.rst.txt b/_sources/index.rst.txt new file mode 100644 index 0000000..b1d2868 --- /dev/null +++ b/_sources/index.rst.txt @@ -0,0 +1,84 @@ +.. fastvpinns documentation master file, created by + sphinx-quickstart on Mon Apr 29 02:17:36 2024. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +Welcome to FastVPINNs's documentation! +====================================== + +.. image:: https://github.com/cmgcds/fastvpinns/actions/workflows/unit-tests.yml/badge.svg + :alt: Unit tests + :target: https://github.com/cmgcds/fastvpinns/actions/workflows/unit-tests.yml + +.. image:: https://github.com/cmgcds/fastvpinns/actions/workflows/integration-tests.yml/badge.svg + :alt: Integration tests + :target: https://github.com/cmgcds/fastvpinns/actions/workflows/integration-tests.yml + +.. image:: https://github.com/cmgcds/fastvpinns/actions/workflows/compatibility-tests.yml/badge.svg + :alt: Compatibility check + :target: https://github.com/cmgcds/fastvpinns/actions/workflows/compatibility-tests.yml + +.. image:: https://codecov.io/gh/cmgcds/fastvpinns/graph/badge.svg?token=NI9G37R2Q7 + :target: https://codecov.io/gh/cmgcds/fastvpinns + :alt: Code coverage + +.. image:: https://img.shields.io/badge/License-MIT-blue.svg + :alt: MIT License + :target: https://opensource.org/licenses/MIT + +.. image:: https://img.shields.io/badge/code%20style-black-000000.svg + :alt: Code style: black + :target: https://github.com/psf/black + +.. image:: https://img.shields.io/badge/python-3.8%20|%203.9%20|%203.10%20|%203.11-blue + :alt: Python Versions + +A robust tensor-based deep learning framework for solving PDE's using hp-Variational Physics-Informed Neural Networks (hp-VPINNs). The framework supports handling complex geometries and uses tensor-based loss computation to accelerate the training of conventional hp-VPINNs. +The framework is based on the work by `FastVPINNs Paper `_. The framework is written on `Tensorflow 2.0 `_ and has support for handling external meshes. + +*Note: This framework is a highly optimised version of the the initial implementation of hp-VPINNs by* `kharazmi `_. Ref `hp-VPINNs(arXiv) `_. + +Variational Physics-informed neural network +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Variational Physics-Informed neural networks are special form of physics informed neural networks, which uses variational form of the loss function to train the NN. A special form of hp-Variational PINNs which uses h- & p- refinement to enhance the ability of the NN to capture higher frequency solutions. +For more details on the theory and implementation of hp-VPINNs, please refer to the `FastVPINNs Paper `_ and `hp-VPINNs Paper `_. + +.. include an image here +.. image:: images/vpinns.png + :alt: VPINNs Image + + +.. toctree:: + :maxdepth: 3 + :caption: Getting Started + + Installation <_rst/_installation.rst> + +.. toctree:: + :maxdepth: 3 + :caption: Example-Problems + + Tutorials <_rst/_tutorial.rst> + +.. toctree:: + :maxdepth: 2 + :caption: API Reference + + fastvpinns <_rst/fastvpinns.rst> + +.. toctree:: + :maxdepth: 1 + :caption: Community + + License <_rst/_licence.rst> + Contributing <_rst/_contributing> + Cite FastVPINNs <_rst/_cite.rst> + Team & Fundings <_rst/_team.rst> + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` diff --git a/_static/Fastvpinns_logo.png b/_static/Fastvpinns_logo.png new file mode 100644 index 0000000..598a20f Binary files /dev/null and b/_static/Fastvpinns_logo.png differ diff --git a/_static/_sphinx_javascript_frameworks_compat.js b/_static/_sphinx_javascript_frameworks_compat.js new file mode 100644 index 0000000..8141580 --- /dev/null +++ b/_static/_sphinx_javascript_frameworks_compat.js @@ -0,0 +1,123 @@ +/* Compatability shim for jQuery and underscores.js. + * + * Copyright Sphinx contributors + * Released under the two clause BSD licence + */ + +/** + * small helper function to urldecode strings + * + * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/decodeURIComponent#Decoding_query_parameters_from_a_URL + */ +jQuery.urldecode = function(x) { + if (!x) { + return x + } + return decodeURIComponent(x.replace(/\+/g, ' ')); +}; + +/** + * small helper function to urlencode strings + */ +jQuery.urlencode = encodeURIComponent; + +/** + * This function returns the parsed url parameters of the + * current request. Multiple values per key are supported, + * it will always return arrays of strings for the value parts. + */ +jQuery.getQueryParameters = function(s) { + if (typeof s === 'undefined') + s = document.location.search; + var parts = s.substr(s.indexOf('?') + 1).split('&'); + var result = {}; + for (var i = 0; i < parts.length; i++) { + var tmp = parts[i].split('=', 2); + var key = jQuery.urldecode(tmp[0]); + var value = jQuery.urldecode(tmp[1]); + if (key in result) + result[key].push(value); + else + result[key] = [value]; + } + return result; +}; + +/** + * highlight a given string on a jquery object by wrapping it in + * span elements with the given class name. + */ +jQuery.fn.highlightText = function(text, className) { + function highlight(node, addItems) { + if (node.nodeType === 3) { + var val = node.nodeValue; + var pos = val.toLowerCase().indexOf(text); + if (pos >= 0 && + !jQuery(node.parentNode).hasClass(className) && + !jQuery(node.parentNode).hasClass("nohighlight")) { + var span; + var isInSVG = jQuery(node).closest("body, svg, foreignObject").is("svg"); + if (isInSVG) { + span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); + } else { + span = document.createElement("span"); + span.className = className; + } + span.appendChild(document.createTextNode(val.substr(pos, text.length))); + node.parentNode.insertBefore(span, node.parentNode.insertBefore( + document.createTextNode(val.substr(pos + text.length)), + node.nextSibling)); + node.nodeValue = val.substr(0, pos); + if (isInSVG) { + var rect = document.createElementNS("http://www.w3.org/2000/svg", "rect"); + var bbox = node.parentElement.getBBox(); + rect.x.baseVal.value = bbox.x; + rect.y.baseVal.value = bbox.y; + rect.width.baseVal.value = bbox.width; + rect.height.baseVal.value = bbox.height; + rect.setAttribute('class', className); + addItems.push({ + "parent": node.parentNode, + "target": rect}); + } + } + } + else if (!jQuery(node).is("button, select, textarea")) { + jQuery.each(node.childNodes, function() { + highlight(this, addItems); + }); + } + } + var addItems = []; + var result = this.each(function() { + highlight(this, addItems); + }); + for (var i = 0; i < addItems.length; ++i) { + jQuery(addItems[i].parent).before(addItems[i].target); + } + return result; +}; + +/* + * backward compatibility for jQuery.browser + * This will be supported until firefox bug is fixed. + */ +if (!jQuery.browser) { + jQuery.uaMatch = function(ua) { + ua = ua.toLowerCase(); + + var match = /(chrome)[ \/]([\w.]+)/.exec(ua) || + /(webkit)[ \/]([\w.]+)/.exec(ua) || + /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) || + /(msie) ([\w.]+)/.exec(ua) || + ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || + []; + + return { + browser: match[ 1 ] || "", + version: match[ 2 ] || "0" + }; + }; + jQuery.browser = {}; + jQuery.browser[jQuery.uaMatch(navigator.userAgent).browser] = true; +} diff --git a/_static/basic.css b/_static/basic.css new file mode 100644 index 0000000..f316efc --- /dev/null +++ b/_static/basic.css @@ -0,0 +1,925 @@ +/* + * basic.css + * ~~~~~~~~~ + * + * Sphinx stylesheet -- basic theme. + * + * :copyright: Copyright 2007-2024 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/* -- main layout ----------------------------------------------------------- */ + +div.clearer { + clear: both; +} + +div.section::after { + display: block; + content: ''; + clear: left; +} + +/* -- relbar ---------------------------------------------------------------- */ + +div.related { + width: 100%; + font-size: 90%; +} + +div.related h3 { + display: none; +} + +div.related ul { + margin: 0; + padding: 0 0 0 10px; + list-style: none; +} + +div.related li { + display: inline; +} + +div.related li.right { + float: right; + margin-right: 5px; +} + +/* -- sidebar --------------------------------------------------------------- */ + +div.sphinxsidebarwrapper { + padding: 10px 5px 0 10px; +} + +div.sphinxsidebar { + float: left; + width: 230px; + margin-left: -100%; + font-size: 90%; + word-wrap: break-word; + overflow-wrap : break-word; +} + +div.sphinxsidebar ul { + list-style: none; +} + +div.sphinxsidebar ul ul, +div.sphinxsidebar ul.want-points { + margin-left: 20px; + list-style: square; +} + +div.sphinxsidebar ul ul { + margin-top: 0; + margin-bottom: 0; +} + +div.sphinxsidebar form { + margin-top: 10px; +} + +div.sphinxsidebar input { + border: 1px solid #98dbcc; + font-family: sans-serif; + font-size: 1em; +} + +div.sphinxsidebar #searchbox form.search { + overflow: hidden; +} + +div.sphinxsidebar #searchbox input[type="text"] { + float: left; + width: 80%; + padding: 0.25em; + box-sizing: border-box; +} + +div.sphinxsidebar #searchbox input[type="submit"] { + float: left; + width: 20%; + border-left: none; + padding: 0.25em; + box-sizing: border-box; +} + + +img { + border: 0; + max-width: 100%; +} + +/* -- search page ----------------------------------------------------------- */ + +ul.search { + margin: 10px 0 0 20px; + padding: 0; +} + +ul.search li { + padding: 5px 0 5px 20px; + background-image: url(file.png); + background-repeat: no-repeat; + background-position: 0 7px; +} + +ul.search li a { + font-weight: bold; +} + +ul.search li p.context { + color: #888; + margin: 2px 0 0 30px; + text-align: left; +} + +ul.keywordmatches li.goodmatch a { + font-weight: bold; +} + +/* -- index page ------------------------------------------------------------ */ + +table.contentstable { + width: 90%; + margin-left: auto; + margin-right: auto; +} + +table.contentstable p.biglink { + line-height: 150%; +} + +a.biglink { + font-size: 1.3em; +} + +span.linkdescr { + font-style: italic; + padding-top: 5px; + font-size: 90%; +} + +/* -- general index --------------------------------------------------------- */ + +table.indextable { + width: 100%; +} + +table.indextable td { + text-align: left; + vertical-align: top; +} + +table.indextable ul { + margin-top: 0; + margin-bottom: 0; + list-style-type: none; +} + +table.indextable > tbody > tr > td > ul { + padding-left: 0em; +} + +table.indextable tr.pcap { + height: 10px; +} + +table.indextable tr.cap { + margin-top: 10px; + background-color: #f2f2f2; +} + +img.toggler { + margin-right: 3px; + margin-top: 3px; + cursor: pointer; +} + +div.modindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +div.genindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +/* -- domain module index --------------------------------------------------- */ + +table.modindextable td { + padding: 2px; + border-collapse: collapse; +} + +/* -- general body styles --------------------------------------------------- */ + +div.body { + min-width: 360px; + max-width: 800px; +} + +div.body p, div.body dd, div.body li, div.body blockquote { + -moz-hyphens: auto; + -ms-hyphens: auto; + -webkit-hyphens: auto; + hyphens: auto; +} + +a.headerlink { + visibility: hidden; +} + +a:visited { + color: #551A8B; +} + +h1:hover > a.headerlink, +h2:hover > a.headerlink, +h3:hover > a.headerlink, +h4:hover > a.headerlink, +h5:hover > a.headerlink, +h6:hover > a.headerlink, +dt:hover > a.headerlink, +caption:hover > a.headerlink, +p.caption:hover > a.headerlink, +div.code-block-caption:hover > a.headerlink { + visibility: visible; +} + +div.body p.caption { + text-align: inherit; +} + +div.body td { + text-align: left; +} + +.first { + margin-top: 0 !important; +} + +p.rubric { + margin-top: 30px; + font-weight: bold; +} + +img.align-left, figure.align-left, .figure.align-left, object.align-left { + clear: left; + float: left; + margin-right: 1em; +} + +img.align-right, figure.align-right, .figure.align-right, object.align-right { + clear: right; + float: right; + margin-left: 1em; +} + +img.align-center, figure.align-center, .figure.align-center, object.align-center { + display: block; + margin-left: auto; + margin-right: auto; +} + +img.align-default, figure.align-default, .figure.align-default { + display: block; + margin-left: auto; + margin-right: auto; +} + +.align-left { + text-align: left; +} + +.align-center { + text-align: center; +} + +.align-default { + text-align: center; +} + +.align-right { + text-align: right; +} + +/* -- sidebars -------------------------------------------------------------- */ + +div.sidebar, +aside.sidebar { + margin: 0 0 0.5em 1em; + border: 1px solid #ddb; + padding: 7px; + background-color: #ffe; + width: 40%; + float: right; + clear: right; + overflow-x: auto; +} + +p.sidebar-title { + font-weight: bold; +} + +nav.contents, +aside.topic, +div.admonition, div.topic, blockquote { + clear: left; +} + +/* -- topics ---------------------------------------------------------------- */ + +nav.contents, +aside.topic, +div.topic { + border: 1px solid #ccc; + padding: 7px; + margin: 10px 0 10px 0; +} + +p.topic-title { + font-size: 1.1em; + font-weight: bold; + margin-top: 10px; +} + +/* -- admonitions ----------------------------------------------------------- */ + +div.admonition { + margin-top: 10px; + margin-bottom: 10px; + padding: 7px; +} + +div.admonition dt { + font-weight: bold; +} + +p.admonition-title { + margin: 0px 10px 5px 0px; + font-weight: bold; +} + +div.body p.centered { + text-align: center; + margin-top: 25px; +} + +/* -- content of sidebars/topics/admonitions -------------------------------- */ + +div.sidebar > :last-child, +aside.sidebar > :last-child, +nav.contents > :last-child, +aside.topic > :last-child, +div.topic > :last-child, +div.admonition > :last-child { + margin-bottom: 0; +} + +div.sidebar::after, +aside.sidebar::after, +nav.contents::after, +aside.topic::after, +div.topic::after, +div.admonition::after, +blockquote::after { + display: block; + content: ''; + clear: both; +} + +/* -- tables ---------------------------------------------------------------- */ + +table.docutils { + margin-top: 10px; + margin-bottom: 10px; + border: 0; + border-collapse: collapse; +} + +table.align-center { + margin-left: auto; + margin-right: auto; +} + +table.align-default { + margin-left: auto; + margin-right: auto; +} + +table caption span.caption-number { + font-style: italic; +} + +table caption span.caption-text { +} + +table.docutils td, table.docutils th { + padding: 1px 8px 1px 5px; + border-top: 0; + border-left: 0; + border-right: 0; + border-bottom: 1px solid #aaa; +} + +th { + text-align: left; + padding-right: 5px; +} + +table.citation { + border-left: solid 1px gray; + margin-left: 1px; +} + +table.citation td { + border-bottom: none; +} + +th > :first-child, +td > :first-child { + margin-top: 0px; +} + +th > :last-child, +td > :last-child { + margin-bottom: 0px; +} + +/* -- figures --------------------------------------------------------------- */ + +div.figure, figure { + margin: 0.5em; + padding: 0.5em; +} + +div.figure p.caption, figcaption { + padding: 0.3em; +} + +div.figure p.caption span.caption-number, +figcaption span.caption-number { + font-style: italic; +} + +div.figure p.caption span.caption-text, +figcaption span.caption-text { +} + +/* -- field list styles ----------------------------------------------------- */ + +table.field-list td, table.field-list th { + border: 0 !important; +} + +.field-list ul { + margin: 0; + padding-left: 1em; +} + +.field-list p { + margin: 0; +} + +.field-name { + -moz-hyphens: manual; + -ms-hyphens: manual; + -webkit-hyphens: manual; + hyphens: manual; +} + +/* -- hlist styles ---------------------------------------------------------- */ + +table.hlist { + margin: 1em 0; +} + +table.hlist td { + vertical-align: top; +} + +/* -- object description styles --------------------------------------------- */ + +.sig { + font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; +} + +.sig-name, code.descname { + background-color: transparent; + font-weight: bold; +} + +.sig-name { + font-size: 1.1em; +} + +code.descname { + font-size: 1.2em; +} + +.sig-prename, code.descclassname { + background-color: transparent; +} + +.optional { + font-size: 1.3em; +} + +.sig-paren { + font-size: larger; +} + +.sig-param.n { + font-style: italic; +} + +/* C++ specific styling */ + +.sig-inline.c-texpr, +.sig-inline.cpp-texpr { + font-family: unset; +} + +.sig.c .k, .sig.c .kt, +.sig.cpp .k, .sig.cpp .kt { + color: #0033B3; +} + +.sig.c .m, +.sig.cpp .m { + color: #1750EB; +} + +.sig.c .s, .sig.c .sc, +.sig.cpp .s, .sig.cpp .sc { + color: #067D17; +} + + +/* -- other body styles ----------------------------------------------------- */ + +ol.arabic { + list-style: decimal; +} + +ol.loweralpha { + list-style: lower-alpha; +} + +ol.upperalpha { + list-style: upper-alpha; +} + +ol.lowerroman { + list-style: lower-roman; +} + +ol.upperroman { + list-style: upper-roman; +} + +:not(li) > ol > li:first-child > :first-child, +:not(li) > ul > li:first-child > :first-child { + margin-top: 0px; +} + +:not(li) > ol > li:last-child > :last-child, +:not(li) > ul > li:last-child > :last-child { + margin-bottom: 0px; +} + +ol.simple ol p, +ol.simple ul p, +ul.simple ol p, +ul.simple ul p { + margin-top: 0; +} + +ol.simple > li:not(:first-child) > p, +ul.simple > li:not(:first-child) > p { + margin-top: 0; +} + +ol.simple p, +ul.simple p { + margin-bottom: 0; +} + +aside.footnote > span, +div.citation > span { + float: left; +} +aside.footnote > span:last-of-type, +div.citation > span:last-of-type { + padding-right: 0.5em; +} +aside.footnote > p { + margin-left: 2em; +} +div.citation > p { + margin-left: 4em; +} +aside.footnote > p:last-of-type, +div.citation > p:last-of-type { + margin-bottom: 0em; +} +aside.footnote > p:last-of-type:after, +div.citation > p:last-of-type:after { + content: ""; + clear: both; +} + +dl.field-list { + display: grid; + grid-template-columns: fit-content(30%) auto; +} + +dl.field-list > dt { + font-weight: bold; + word-break: break-word; + padding-left: 0.5em; + padding-right: 5px; +} + +dl.field-list > dd { + padding-left: 0.5em; + margin-top: 0em; + margin-left: 0em; + margin-bottom: 0em; +} + +dl { + margin-bottom: 15px; +} + +dd > :first-child { + margin-top: 0px; +} + +dd ul, dd table { + margin-bottom: 10px; +} + +dd { + margin-top: 3px; + margin-bottom: 10px; + margin-left: 30px; +} + +.sig dd { + margin-top: 0px; + margin-bottom: 0px; +} + +.sig dl { + margin-top: 0px; + margin-bottom: 0px; +} + +dl > dd:last-child, +dl > dd:last-child > :last-child { + margin-bottom: 0; +} + +dt:target, span.highlighted { + background-color: #fbe54e; +} + +rect.highlighted { + fill: #fbe54e; +} + +dl.glossary dt { + font-weight: bold; + font-size: 1.1em; +} + +.versionmodified { + font-style: italic; +} + +.system-message { + background-color: #fda; + padding: 5px; + border: 3px solid red; +} + +.footnote:target { + background-color: #ffa; +} + +.line-block { + display: block; + margin-top: 1em; + margin-bottom: 1em; +} + +.line-block .line-block { + margin-top: 0; + margin-bottom: 0; + margin-left: 1.5em; +} + +.guilabel, .menuselection { + font-family: sans-serif; +} + +.accelerator { + text-decoration: underline; +} + +.classifier { + font-style: oblique; +} + +.classifier:before { + font-style: normal; + margin: 0 0.5em; + content: ":"; + display: inline-block; +} + +abbr, acronym { + border-bottom: dotted 1px; + cursor: help; +} + +.translated { + background-color: rgba(207, 255, 207, 0.2) +} + +.untranslated { + background-color: rgba(255, 207, 207, 0.2) +} + +/* -- code displays --------------------------------------------------------- */ + +pre { + overflow: auto; + overflow-y: hidden; /* fixes display issues on Chrome browsers */ +} + +pre, div[class*="highlight-"] { + clear: both; +} + +span.pre { + -moz-hyphens: none; + -ms-hyphens: none; + -webkit-hyphens: none; + hyphens: none; + white-space: nowrap; +} + +div[class*="highlight-"] { + margin: 1em 0; +} + +td.linenos pre { + border: 0; + background-color: transparent; + color: #aaa; +} + +table.highlighttable { + display: block; +} + +table.highlighttable tbody { + display: block; +} + +table.highlighttable tr { + display: flex; +} + +table.highlighttable td { + margin: 0; + padding: 0; +} + +table.highlighttable td.linenos { + padding-right: 0.5em; +} + +table.highlighttable td.code { + flex: 1; + overflow: hidden; +} + +.highlight .hll { + display: block; +} + +div.highlight pre, +table.highlighttable pre { + margin: 0; +} + +div.code-block-caption + div { + margin-top: 0; +} + +div.code-block-caption { + margin-top: 1em; + padding: 2px 5px; + font-size: small; +} + +div.code-block-caption code { + background-color: transparent; +} + +table.highlighttable td.linenos, +span.linenos, +div.highlight span.gp { /* gp: Generic.Prompt */ + user-select: none; + -webkit-user-select: text; /* Safari fallback only */ + -webkit-user-select: none; /* Chrome/Safari */ + -moz-user-select: none; /* Firefox */ + -ms-user-select: none; /* IE10+ */ +} + +div.code-block-caption span.caption-number { + padding: 0.1em 0.3em; + font-style: italic; +} + +div.code-block-caption span.caption-text { +} + +div.literal-block-wrapper { + margin: 1em 0; +} + +code.xref, a code { + background-color: transparent; + font-weight: bold; +} + +h1 code, h2 code, h3 code, h4 code, h5 code, h6 code { + background-color: transparent; +} + +.viewcode-link { + float: right; +} + +.viewcode-back { + float: right; + font-family: sans-serif; +} + +div.viewcode-block:target { + margin: -1px -10px; + padding: 0 10px; +} + +/* -- math display ---------------------------------------------------------- */ + +img.math { + vertical-align: middle; +} + +div.body div.math p { + text-align: center; +} + +span.eqno { + float: right; +} + +span.eqno a.headerlink { + position: absolute; + z-index: 1; +} + +div.math:hover a.headerlink { + visibility: visible; +} + +/* -- printout stylesheet --------------------------------------------------- */ + +@media print { + div.document, + div.documentwrapper, + div.bodywrapper { + margin: 0 !important; + width: 100%; + } + + div.sphinxsidebar, + div.related, + div.footer, + #top-link { + display: none; + } +} \ No newline at end of file diff --git a/_static/check-solid.svg b/_static/check-solid.svg new file mode 100644 index 0000000..92fad4b --- /dev/null +++ b/_static/check-solid.svg @@ -0,0 +1,4 @@ + + + + diff --git a/_static/clipboard.min.js b/_static/clipboard.min.js new file mode 100644 index 0000000..54b3c46 --- /dev/null +++ b/_static/clipboard.min.js @@ -0,0 +1,7 @@ +/*! + * clipboard.js v2.0.8 + * https://clipboardjs.com/ + * + * Licensed MIT © Zeno Rocha + */ +!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.ClipboardJS=e():t.ClipboardJS=e()}(this,function(){return n={686:function(t,e,n){"use strict";n.d(e,{default:function(){return o}});var e=n(279),i=n.n(e),e=n(370),u=n.n(e),e=n(817),c=n.n(e);function a(t){try{return document.execCommand(t)}catch(t){return}}var f=function(t){t=c()(t);return a("cut"),t};var l=function(t){var e,n,o,r=1 + + + + diff --git a/_static/copybutton.css b/_static/copybutton.css new file mode 100644 index 0000000..f1916ec --- /dev/null +++ b/_static/copybutton.css @@ -0,0 +1,94 @@ +/* Copy buttons */ +button.copybtn { + position: absolute; + display: flex; + top: .3em; + right: .3em; + width: 1.7em; + height: 1.7em; + opacity: 0; + transition: opacity 0.3s, border .3s, background-color .3s; + user-select: none; + padding: 0; + border: none; + outline: none; + border-radius: 0.4em; + /* The colors that GitHub uses */ + border: #1b1f2426 1px solid; + background-color: #f6f8fa; + color: #57606a; +} + +button.copybtn.success { + border-color: #22863a; + color: #22863a; +} + +button.copybtn svg { + stroke: currentColor; + width: 1.5em; + height: 1.5em; + padding: 0.1em; +} + +div.highlight { + position: relative; +} + +/* Show the copybutton */ +.highlight:hover button.copybtn, button.copybtn.success { + opacity: 1; +} + +.highlight button.copybtn:hover { + background-color: rgb(235, 235, 235); +} + +.highlight button.copybtn:active { + background-color: rgb(187, 187, 187); +} + +/** + * A minimal CSS-only tooltip copied from: + * https://codepen.io/mildrenben/pen/rVBrpK + * + * To use, write HTML like the following: + * + *

Short

+ */ + .o-tooltip--left { + position: relative; + } + + .o-tooltip--left:after { + opacity: 0; + visibility: hidden; + position: absolute; + content: attr(data-tooltip); + padding: .2em; + font-size: .8em; + left: -.2em; + background: grey; + color: white; + white-space: nowrap; + z-index: 2; + border-radius: 2px; + transform: translateX(-102%) translateY(0); + transition: opacity 0.2s cubic-bezier(0.64, 0.09, 0.08, 1), transform 0.2s cubic-bezier(0.64, 0.09, 0.08, 1); +} + +.o-tooltip--left:hover:after { + display: block; + opacity: 1; + visibility: visible; + transform: translateX(-100%) translateY(0); + transition: opacity 0.2s cubic-bezier(0.64, 0.09, 0.08, 1), transform 0.2s cubic-bezier(0.64, 0.09, 0.08, 1); + transition-delay: .5s; +} + +/* By default the copy button shouldn't show up when printing a page */ +@media print { + button.copybtn { + display: none; + } +} diff --git a/_static/copybutton.js b/_static/copybutton.js new file mode 100644 index 0000000..2ea7ff3 --- /dev/null +++ b/_static/copybutton.js @@ -0,0 +1,248 @@ +// Localization support +const messages = { + 'en': { + 'copy': 'Copy', + 'copy_to_clipboard': 'Copy to clipboard', + 'copy_success': 'Copied!', + 'copy_failure': 'Failed to copy', + }, + 'es' : { + 'copy': 'Copiar', + 'copy_to_clipboard': 'Copiar al portapapeles', + 'copy_success': '¡Copiado!', + 'copy_failure': 'Error al copiar', + }, + 'de' : { + 'copy': 'Kopieren', + 'copy_to_clipboard': 'In die Zwischenablage kopieren', + 'copy_success': 'Kopiert!', + 'copy_failure': 'Fehler beim Kopieren', + }, + 'fr' : { + 'copy': 'Copier', + 'copy_to_clipboard': 'Copier dans le presse-papier', + 'copy_success': 'Copié !', + 'copy_failure': 'Échec de la copie', + }, + 'ru': { + 'copy': 'Скопировать', + 'copy_to_clipboard': 'Скопировать в буфер', + 'copy_success': 'Скопировано!', + 'copy_failure': 'Не удалось скопировать', + }, + 'zh-CN': { + 'copy': '复制', + 'copy_to_clipboard': '复制到剪贴板', + 'copy_success': '复制成功!', + 'copy_failure': '复制失败', + }, + 'it' : { + 'copy': 'Copiare', + 'copy_to_clipboard': 'Copiato negli appunti', + 'copy_success': 'Copiato!', + 'copy_failure': 'Errore durante la copia', + } +} + +let locale = 'en' +if( document.documentElement.lang !== undefined + && messages[document.documentElement.lang] !== undefined ) { + locale = document.documentElement.lang +} + +let doc_url_root = DOCUMENTATION_OPTIONS.URL_ROOT; +if (doc_url_root == '#') { + doc_url_root = ''; +} + +/** + * SVG files for our copy buttons + */ +let iconCheck = ` + ${messages[locale]['copy_success']} + + +` + +// If the user specified their own SVG use that, otherwise use the default +let iconCopy = ``; +if (!iconCopy) { + iconCopy = ` + ${messages[locale]['copy_to_clipboard']} + + + +` +} + +/** + * Set up copy/paste for code blocks + */ + +const runWhenDOMLoaded = cb => { + if (document.readyState != 'loading') { + cb() + } else if (document.addEventListener) { + document.addEventListener('DOMContentLoaded', cb) + } else { + document.attachEvent('onreadystatechange', function() { + if (document.readyState == 'complete') cb() + }) + } +} + +const codeCellId = index => `codecell${index}` + +// Clears selected text since ClipboardJS will select the text when copying +const clearSelection = () => { + if (window.getSelection) { + window.getSelection().removeAllRanges() + } else if (document.selection) { + document.selection.empty() + } +} + +// Changes tooltip text for a moment, then changes it back +// We want the timeout of our `success` class to be a bit shorter than the +// tooltip and icon change, so that we can hide the icon before changing back. +var timeoutIcon = 2000; +var timeoutSuccessClass = 1500; + +const temporarilyChangeTooltip = (el, oldText, newText) => { + el.setAttribute('data-tooltip', newText) + el.classList.add('success') + // Remove success a little bit sooner than we change the tooltip + // So that we can use CSS to hide the copybutton first + setTimeout(() => el.classList.remove('success'), timeoutSuccessClass) + setTimeout(() => el.setAttribute('data-tooltip', oldText), timeoutIcon) +} + +// Changes the copy button icon for two seconds, then changes it back +const temporarilyChangeIcon = (el) => { + el.innerHTML = iconCheck; + setTimeout(() => {el.innerHTML = iconCopy}, timeoutIcon) +} + +const addCopyButtonToCodeCells = () => { + // If ClipboardJS hasn't loaded, wait a bit and try again. This + // happens because we load ClipboardJS asynchronously. + if (window.ClipboardJS === undefined) { + setTimeout(addCopyButtonToCodeCells, 250) + return + } + + // Add copybuttons to all of our code cells + const COPYBUTTON_SELECTOR = 'div.highlight pre'; + const codeCells = document.querySelectorAll(COPYBUTTON_SELECTOR) + codeCells.forEach((codeCell, index) => { + const id = codeCellId(index) + codeCell.setAttribute('id', id) + + const clipboardButton = id => + `` + codeCell.insertAdjacentHTML('afterend', clipboardButton(id)) + }) + +function escapeRegExp(string) { + return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string +} + +/** + * Removes excluded text from a Node. + * + * @param {Node} target Node to filter. + * @param {string} exclude CSS selector of nodes to exclude. + * @returns {DOMString} Text from `target` with text removed. + */ +function filterText(target, exclude) { + const clone = target.cloneNode(true); // clone as to not modify the live DOM + if (exclude) { + // remove excluded nodes + clone.querySelectorAll(exclude).forEach(node => node.remove()); + } + return clone.innerText; +} + +// Callback when a copy button is clicked. Will be passed the node that was clicked +// should then grab the text and replace pieces of text that shouldn't be used in output +function formatCopyText(textContent, copybuttonPromptText, isRegexp = false, onlyCopyPromptLines = true, removePrompts = true, copyEmptyLines = true, lineContinuationChar = "", hereDocDelim = "") { + var regexp; + var match; + + // Do we check for line continuation characters and "HERE-documents"? + var useLineCont = !!lineContinuationChar + var useHereDoc = !!hereDocDelim + + // create regexp to capture prompt and remaining line + if (isRegexp) { + regexp = new RegExp('^(' + copybuttonPromptText + ')(.*)') + } else { + regexp = new RegExp('^(' + escapeRegExp(copybuttonPromptText) + ')(.*)') + } + + const outputLines = []; + var promptFound = false; + var gotLineCont = false; + var gotHereDoc = false; + const lineGotPrompt = []; + for (const line of textContent.split('\n')) { + match = line.match(regexp) + if (match || gotLineCont || gotHereDoc) { + promptFound = regexp.test(line) + lineGotPrompt.push(promptFound) + if (removePrompts && promptFound) { + outputLines.push(match[2]) + } else { + outputLines.push(line) + } + gotLineCont = line.endsWith(lineContinuationChar) & useLineCont + if (line.includes(hereDocDelim) & useHereDoc) + gotHereDoc = !gotHereDoc + } else if (!onlyCopyPromptLines) { + outputLines.push(line) + } else if (copyEmptyLines && line.trim() === '') { + outputLines.push(line) + } + } + + // If no lines with the prompt were found then just use original lines + if (lineGotPrompt.some(v => v === true)) { + textContent = outputLines.join('\n'); + } + + // Remove a trailing newline to avoid auto-running when pasting + if (textContent.endsWith("\n")) { + textContent = textContent.slice(0, -1) + } + return textContent +} + + +var copyTargetText = (trigger) => { + var target = document.querySelector(trigger.attributes['data-clipboard-target'].value); + + // get filtered text + let exclude = '.linenos'; + + let text = filterText(target, exclude); + return formatCopyText(text, '', false, true, true, true, '', '') +} + + // Initialize with a callback so we can modify the text before copy + const clipboard = new ClipboardJS('.copybtn', {text: copyTargetText}) + + // Update UI with error/success messages + clipboard.on('success', event => { + clearSelection() + temporarilyChangeTooltip(event.trigger, messages[locale]['copy'], messages[locale]['copy_success']) + temporarilyChangeIcon(event.trigger) + }) + + clipboard.on('error', event => { + temporarilyChangeTooltip(event.trigger, messages[locale]['copy'], messages[locale]['copy_failure']) + }) +} + +runWhenDOMLoaded(addCopyButtonToCodeCells) \ No newline at end of file diff --git a/_static/copybutton_funcs.js b/_static/copybutton_funcs.js new file mode 100644 index 0000000..dbe1aaa --- /dev/null +++ b/_static/copybutton_funcs.js @@ -0,0 +1,73 @@ +function escapeRegExp(string) { + return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string +} + +/** + * Removes excluded text from a Node. + * + * @param {Node} target Node to filter. + * @param {string} exclude CSS selector of nodes to exclude. + * @returns {DOMString} Text from `target` with text removed. + */ +export function filterText(target, exclude) { + const clone = target.cloneNode(true); // clone as to not modify the live DOM + if (exclude) { + // remove excluded nodes + clone.querySelectorAll(exclude).forEach(node => node.remove()); + } + return clone.innerText; +} + +// Callback when a copy button is clicked. Will be passed the node that was clicked +// should then grab the text and replace pieces of text that shouldn't be used in output +export function formatCopyText(textContent, copybuttonPromptText, isRegexp = false, onlyCopyPromptLines = true, removePrompts = true, copyEmptyLines = true, lineContinuationChar = "", hereDocDelim = "") { + var regexp; + var match; + + // Do we check for line continuation characters and "HERE-documents"? + var useLineCont = !!lineContinuationChar + var useHereDoc = !!hereDocDelim + + // create regexp to capture prompt and remaining line + if (isRegexp) { + regexp = new RegExp('^(' + copybuttonPromptText + ')(.*)') + } else { + regexp = new RegExp('^(' + escapeRegExp(copybuttonPromptText) + ')(.*)') + } + + const outputLines = []; + var promptFound = false; + var gotLineCont = false; + var gotHereDoc = false; + const lineGotPrompt = []; + for (const line of textContent.split('\n')) { + match = line.match(regexp) + if (match || gotLineCont || gotHereDoc) { + promptFound = regexp.test(line) + lineGotPrompt.push(promptFound) + if (removePrompts && promptFound) { + outputLines.push(match[2]) + } else { + outputLines.push(line) + } + gotLineCont = line.endsWith(lineContinuationChar) & useLineCont + if (line.includes(hereDocDelim) & useHereDoc) + gotHereDoc = !gotHereDoc + } else if (!onlyCopyPromptLines) { + outputLines.push(line) + } else if (copyEmptyLines && line.trim() === '') { + outputLines.push(line) + } + } + + // If no lines with the prompt were found then just use original lines + if (lineGotPrompt.some(v => v === true)) { + textContent = outputLines.join('\n'); + } + + // Remove a trailing newline to avoid auto-running when pasting + if (textContent.endsWith("\n")) { + textContent = textContent.slice(0, -1) + } + return textContent +} diff --git a/_static/css/badge_only.css b/_static/css/badge_only.css new file mode 100644 index 0000000..c718cee --- /dev/null +++ b/_static/css/badge_only.css @@ -0,0 +1 @@ +.clearfix{*zoom:1}.clearfix:after,.clearfix:before{display:table;content:""}.clearfix:after{clear:both}@font-face{font-family:FontAwesome;font-style:normal;font-weight:400;src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713?#iefix) format("embedded-opentype"),url(fonts/fontawesome-webfont.woff2?af7ae505a9eed503f8b8e6982036873e) format("woff2"),url(fonts/fontawesome-webfont.woff?fee66e712a8a08eef5805a46892932ad) format("woff"),url(fonts/fontawesome-webfont.ttf?b06871f281fee6b241d60582ae9369b9) format("truetype"),url(fonts/fontawesome-webfont.svg?912ec66d7572ff821749319396470bde#FontAwesome) format("svg")}.fa:before{font-family:FontAwesome;font-style:normal;font-weight:400;line-height:1}.fa:before,a .fa{text-decoration:inherit}.fa:before,a .fa,li .fa{display:inline-block}li .fa-large:before{width:1.875em}ul.fas{list-style-type:none;margin-left:2em;text-indent:-.8em}ul.fas li .fa{width:.8em}ul.fas li .fa-large:before{vertical-align:baseline}.fa-book:before,.icon-book:before{content:"\f02d"}.fa-caret-down:before,.icon-caret-down:before{content:"\f0d7"}.fa-caret-up:before,.icon-caret-up:before{content:"\f0d8"}.fa-caret-left:before,.icon-caret-left:before{content:"\f0d9"}.fa-caret-right:before,.icon-caret-right:before{content:"\f0da"}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;z-index:400}.rst-versions a{color:#2980b9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27ae60}.rst-versions .rst-current-version:after{clear:both;content:"";display:block}.rst-versions .rst-current-version .fa{color:#fcfcfc}.rst-versions .rst-current-version .fa-book,.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#e74c3c;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#f1c40f;color:#000}.rst-versions.shift-up{height:auto;max-height:100%;overflow-y:scroll}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:grey;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:1px solid #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px;max-height:90%}.rst-versions.rst-badge .fa-book,.rst-versions.rst-badge .icon-book{float:none;line-height:30px}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book,.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge>.rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width:768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}} \ No newline at end of file diff --git a/_static/css/fonts/Roboto-Slab-Bold.woff b/_static/css/fonts/Roboto-Slab-Bold.woff new file mode 100644 index 0000000..6cb6000 Binary files /dev/null and b/_static/css/fonts/Roboto-Slab-Bold.woff differ diff --git a/_static/css/fonts/Roboto-Slab-Bold.woff2 b/_static/css/fonts/Roboto-Slab-Bold.woff2 new file mode 100644 index 0000000..7059e23 Binary files /dev/null and b/_static/css/fonts/Roboto-Slab-Bold.woff2 differ diff --git a/_static/css/fonts/Roboto-Slab-Regular.woff b/_static/css/fonts/Roboto-Slab-Regular.woff new file mode 100644 index 0000000..f815f63 Binary files /dev/null and b/_static/css/fonts/Roboto-Slab-Regular.woff differ diff --git a/_static/css/fonts/Roboto-Slab-Regular.woff2 b/_static/css/fonts/Roboto-Slab-Regular.woff2 new file mode 100644 index 0000000..f2c76e5 Binary files /dev/null and b/_static/css/fonts/Roboto-Slab-Regular.woff2 differ diff --git a/_static/css/fonts/fontawesome-webfont.eot b/_static/css/fonts/fontawesome-webfont.eot new file mode 100644 index 0000000..e9f60ca Binary files /dev/null and b/_static/css/fonts/fontawesome-webfont.eot differ diff --git a/_static/css/fonts/fontawesome-webfont.svg b/_static/css/fonts/fontawesome-webfont.svg new file mode 100644 index 0000000..855c845 --- /dev/null +++ b/_static/css/fonts/fontawesome-webfont.svg @@ -0,0 +1,2671 @@ + + + + +Created by FontForge 20120731 at Mon Oct 24 17:37:40 2016 + By ,,, +Copyright Dave Gandy 2016. All rights reserved. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/_static/css/fonts/fontawesome-webfont.ttf b/_static/css/fonts/fontawesome-webfont.ttf new file mode 100644 index 0000000..35acda2 Binary files /dev/null and b/_static/css/fonts/fontawesome-webfont.ttf differ diff --git a/_static/css/fonts/fontawesome-webfont.woff b/_static/css/fonts/fontawesome-webfont.woff new file mode 100644 index 0000000..400014a Binary files /dev/null and b/_static/css/fonts/fontawesome-webfont.woff differ diff --git a/_static/css/fonts/fontawesome-webfont.woff2 b/_static/css/fonts/fontawesome-webfont.woff2 new file mode 100644 index 0000000..4d13fc6 Binary files /dev/null and b/_static/css/fonts/fontawesome-webfont.woff2 differ diff --git a/_static/css/fonts/lato-bold-italic.woff b/_static/css/fonts/lato-bold-italic.woff new file mode 100644 index 0000000..88ad05b Binary files /dev/null and b/_static/css/fonts/lato-bold-italic.woff differ diff --git a/_static/css/fonts/lato-bold-italic.woff2 b/_static/css/fonts/lato-bold-italic.woff2 new file mode 100644 index 0000000..c4e3d80 Binary files /dev/null and b/_static/css/fonts/lato-bold-italic.woff2 differ diff --git a/_static/css/fonts/lato-bold.woff b/_static/css/fonts/lato-bold.woff new file mode 100644 index 0000000..c6dff51 Binary files /dev/null and b/_static/css/fonts/lato-bold.woff differ diff --git a/_static/css/fonts/lato-bold.woff2 b/_static/css/fonts/lato-bold.woff2 new file mode 100644 index 0000000..bb19504 Binary files /dev/null and b/_static/css/fonts/lato-bold.woff2 differ diff --git a/_static/css/fonts/lato-normal-italic.woff b/_static/css/fonts/lato-normal-italic.woff new file mode 100644 index 0000000..76114bc Binary files /dev/null and b/_static/css/fonts/lato-normal-italic.woff differ diff --git a/_static/css/fonts/lato-normal-italic.woff2 b/_static/css/fonts/lato-normal-italic.woff2 new file mode 100644 index 0000000..3404f37 Binary files /dev/null and b/_static/css/fonts/lato-normal-italic.woff2 differ diff --git a/_static/css/fonts/lato-normal.woff b/_static/css/fonts/lato-normal.woff new file mode 100644 index 0000000..ae1307f Binary files /dev/null and b/_static/css/fonts/lato-normal.woff differ diff --git a/_static/css/fonts/lato-normal.woff2 b/_static/css/fonts/lato-normal.woff2 new file mode 100644 index 0000000..3bf9843 Binary files /dev/null and b/_static/css/fonts/lato-normal.woff2 differ diff --git a/_static/css/theme.css b/_static/css/theme.css new file mode 100644 index 0000000..19a446a --- /dev/null +++ b/_static/css/theme.css @@ -0,0 +1,4 @@ +html{box-sizing:border-box}*,:after,:before{box-sizing:inherit}article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block}audio,canvas,video{display:inline-block;*display:inline;*zoom:1}[hidden],audio:not([controls]){display:none}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}blockquote{margin:0}dfn{font-style:italic}ins{background:#ff9;text-decoration:none}ins,mark{color:#000}mark{background:#ff0;font-style:italic;font-weight:700}.rst-content code,.rst-content tt,code,kbd,pre,samp{font-family:monospace,serif;_font-family:courier new,monospace;font-size:1em}pre{white-space:pre}q{quotes:none}q:after,q:before{content:"";content:none}small{font-size:85%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}dl,ol,ul{margin:0;padding:0;list-style:none;list-style-image:none}li{list-style:none}dd{margin:0}img{border:0;-ms-interpolation-mode:bicubic;vertical-align:middle;max-width:100%}svg:not(:root){overflow:hidden}figure,form{margin:0}label{cursor:pointer}button,input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}button,input{line-height:normal}button,input[type=button],input[type=reset],input[type=submit]{cursor:pointer;-webkit-appearance:button;*overflow:visible}button[disabled],input[disabled]{cursor:default}input[type=search]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}textarea{resize:vertical}table{border-collapse:collapse;border-spacing:0}td{vertical-align:top}.chromeframe{margin:.2em 0;background:#ccc;color:#000;padding:.2em 0}.ir{display:block;border:0;text-indent:-999em;overflow:hidden;background-color:transparent;background-repeat:no-repeat;text-align:left;direction:ltr;*line-height:0}.ir br{display:none}.hidden{display:none!important;visibility:hidden}.visuallyhidden{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.visuallyhidden.focusable:active,.visuallyhidden.focusable:focus{clip:auto;height:auto;margin:0;overflow:visible;position:static;width:auto}.invisible{visibility:hidden}.relative{position:relative}big,small{font-size:100%}@media print{body,html,section{background:none!important}*{box-shadow:none!important;text-shadow:none!important;filter:none!important;-ms-filter:none!important}a,a:visited{text-decoration:underline}.ir a:after,a[href^="#"]:after,a[href^="javascript:"]:after{content:""}blockquote,pre{page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}img{max-width:100%!important}@page{margin:.5cm}.rst-content .toctree-wrapper>p.caption,h2,h3,p{orphans:3;widows:3}.rst-content .toctree-wrapper>p.caption,h2,h3{page-break-after:avoid}}.btn,.fa:before,.icon:before,.rst-content .admonition,.rst-content .admonition-title:before,.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .code-block-caption .headerlink:before,.rst-content .danger,.rst-content .eqno .headerlink:before,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .note,.rst-content .seealso,.rst-content .tip,.rst-content .warning,.rst-content code.download span:first-child:before,.rst-content dl dt .headerlink:before,.rst-content h1 .headerlink:before,.rst-content h2 .headerlink:before,.rst-content h3 .headerlink:before,.rst-content h4 .headerlink:before,.rst-content h5 .headerlink:before,.rst-content h6 .headerlink:before,.rst-content p.caption .headerlink:before,.rst-content p .headerlink:before,.rst-content table>caption .headerlink:before,.rst-content tt.download span:first-child:before,.wy-alert,.wy-dropdown .caret:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-menu-vertical li.current>a button.toctree-expand:before,.wy-menu-vertical li.on a button.toctree-expand:before,.wy-menu-vertical li button.toctree-expand:before,input[type=color],input[type=date],input[type=datetime-local],input[type=datetime],input[type=email],input[type=month],input[type=number],input[type=password],input[type=search],input[type=tel],input[type=text],input[type=time],input[type=url],input[type=week],select,textarea{-webkit-font-smoothing:antialiased}.clearfix{*zoom:1}.clearfix:after,.clearfix:before{display:table;content:""}.clearfix:after{clear:both}/*! + * Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome + * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) + */@font-face{font-family:FontAwesome;src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713);src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713?#iefix&v=4.7.0) format("embedded-opentype"),url(fonts/fontawesome-webfont.woff2?af7ae505a9eed503f8b8e6982036873e) format("woff2"),url(fonts/fontawesome-webfont.woff?fee66e712a8a08eef5805a46892932ad) format("woff"),url(fonts/fontawesome-webfont.ttf?b06871f281fee6b241d60582ae9369b9) format("truetype"),url(fonts/fontawesome-webfont.svg?912ec66d7572ff821749319396470bde#fontawesomeregular) format("svg");font-weight:400;font-style:normal}.fa,.icon,.rst-content .admonition-title,.rst-content .code-block-caption .headerlink,.rst-content .eqno .headerlink,.rst-content code.download span:first-child,.rst-content dl dt .headerlink,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content p.caption .headerlink,.rst-content p .headerlink,.rst-content table>caption .headerlink,.rst-content tt.download span:first-child,.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand,.wy-menu-vertical li button.toctree-expand{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-lg{font-size:1.33333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14286em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14286em;width:2.14286em;top:.14286em;text-align:center}.fa-li.fa-lg{left:-1.85714em}.fa-border{padding:.2em .25em .15em;border:.08em solid #eee;border-radius:.1em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa-pull-left.icon,.fa.fa-pull-left,.rst-content .code-block-caption .fa-pull-left.headerlink,.rst-content .eqno .fa-pull-left.headerlink,.rst-content .fa-pull-left.admonition-title,.rst-content code.download span.fa-pull-left:first-child,.rst-content dl dt .fa-pull-left.headerlink,.rst-content h1 .fa-pull-left.headerlink,.rst-content h2 .fa-pull-left.headerlink,.rst-content h3 .fa-pull-left.headerlink,.rst-content h4 .fa-pull-left.headerlink,.rst-content h5 .fa-pull-left.headerlink,.rst-content h6 .fa-pull-left.headerlink,.rst-content p .fa-pull-left.headerlink,.rst-content table>caption .fa-pull-left.headerlink,.rst-content tt.download span.fa-pull-left:first-child,.wy-menu-vertical li.current>a button.fa-pull-left.toctree-expand,.wy-menu-vertical li.on a button.fa-pull-left.toctree-expand,.wy-menu-vertical li button.fa-pull-left.toctree-expand{margin-right:.3em}.fa-pull-right.icon,.fa.fa-pull-right,.rst-content .code-block-caption .fa-pull-right.headerlink,.rst-content .eqno .fa-pull-right.headerlink,.rst-content .fa-pull-right.admonition-title,.rst-content code.download span.fa-pull-right:first-child,.rst-content dl dt .fa-pull-right.headerlink,.rst-content h1 .fa-pull-right.headerlink,.rst-content h2 .fa-pull-right.headerlink,.rst-content h3 .fa-pull-right.headerlink,.rst-content h4 .fa-pull-right.headerlink,.rst-content h5 .fa-pull-right.headerlink,.rst-content h6 .fa-pull-right.headerlink,.rst-content p .fa-pull-right.headerlink,.rst-content table>caption .fa-pull-right.headerlink,.rst-content tt.download span.fa-pull-right:first-child,.wy-menu-vertical li.current>a button.fa-pull-right.toctree-expand,.wy-menu-vertical li.on a button.fa-pull-right.toctree-expand,.wy-menu-vertical li button.fa-pull-right.toctree-expand{margin-left:.3em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left,.pull-left.icon,.rst-content .code-block-caption .pull-left.headerlink,.rst-content .eqno .pull-left.headerlink,.rst-content .pull-left.admonition-title,.rst-content code.download span.pull-left:first-child,.rst-content dl dt .pull-left.headerlink,.rst-content h1 .pull-left.headerlink,.rst-content h2 .pull-left.headerlink,.rst-content h3 .pull-left.headerlink,.rst-content h4 .pull-left.headerlink,.rst-content h5 .pull-left.headerlink,.rst-content h6 .pull-left.headerlink,.rst-content p .pull-left.headerlink,.rst-content table>caption .pull-left.headerlink,.rst-content tt.download span.pull-left:first-child,.wy-menu-vertical li.current>a button.pull-left.toctree-expand,.wy-menu-vertical li.on a button.pull-left.toctree-expand,.wy-menu-vertical li button.pull-left.toctree-expand{margin-right:.3em}.fa.pull-right,.pull-right.icon,.rst-content .code-block-caption .pull-right.headerlink,.rst-content .eqno .pull-right.headerlink,.rst-content .pull-right.admonition-title,.rst-content code.download span.pull-right:first-child,.rst-content dl dt .pull-right.headerlink,.rst-content h1 .pull-right.headerlink,.rst-content h2 .pull-right.headerlink,.rst-content h3 .pull-right.headerlink,.rst-content h4 .pull-right.headerlink,.rst-content h5 .pull-right.headerlink,.rst-content h6 .pull-right.headerlink,.rst-content p .pull-right.headerlink,.rst-content table>caption .pull-right.headerlink,.rst-content tt.download span.pull-right:first-child,.wy-menu-vertical li.current>a button.pull-right.toctree-expand,.wy-menu-vertical li.on a button.pull-right.toctree-expand,.wy-menu-vertical li button.pull-right.toctree-expand{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s linear infinite;animation:fa-spin 2s linear infinite}.fa-pulse{-webkit-animation:fa-spin 1s steps(8) infinite;animation:fa-spin 1s steps(8) infinite}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";-webkit-transform:scaleX(-1);-ms-transform:scaleX(-1);transform:scaleX(-1)}.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)";-webkit-transform:scaleY(-1);-ms-transform:scaleY(-1);transform:scaleY(-1)}:root .fa-flip-horizontal,:root .fa-flip-vertical,:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:""}.fa-music:before{content:""}.fa-search:before,.icon-search:before{content:""}.fa-envelope-o:before{content:""}.fa-heart:before{content:""}.fa-star:before{content:""}.fa-star-o:before{content:""}.fa-user:before{content:""}.fa-film:before{content:""}.fa-th-large:before{content:""}.fa-th:before{content:""}.fa-th-list:before{content:""}.fa-check:before{content:""}.fa-close:before,.fa-remove:before,.fa-times:before{content:""}.fa-search-plus:before{content:""}.fa-search-minus:before{content:""}.fa-power-off:before{content:""}.fa-signal:before{content:""}.fa-cog:before,.fa-gear:before{content:""}.fa-trash-o:before{content:""}.fa-home:before,.icon-home:before{content:""}.fa-file-o:before{content:""}.fa-clock-o:before{content:""}.fa-road:before{content:""}.fa-download:before,.rst-content code.download span:first-child:before,.rst-content tt.download span:first-child:before{content:""}.fa-arrow-circle-o-down:before{content:""}.fa-arrow-circle-o-up:before{content:""}.fa-inbox:before{content:""}.fa-play-circle-o:before{content:""}.fa-repeat:before,.fa-rotate-right:before{content:""}.fa-refresh:before{content:""}.fa-list-alt:before{content:""}.fa-lock:before{content:""}.fa-flag:before{content:""}.fa-headphones:before{content:""}.fa-volume-off:before{content:""}.fa-volume-down:before{content:""}.fa-volume-up:before{content:""}.fa-qrcode:before{content:""}.fa-barcode:before{content:""}.fa-tag:before{content:""}.fa-tags:before{content:""}.fa-book:before,.icon-book:before{content:""}.fa-bookmark:before{content:""}.fa-print:before{content:""}.fa-camera:before{content:""}.fa-font:before{content:""}.fa-bold:before{content:""}.fa-italic:before{content:""}.fa-text-height:before{content:""}.fa-text-width:before{content:""}.fa-align-left:before{content:""}.fa-align-center:before{content:""}.fa-align-right:before{content:""}.fa-align-justify:before{content:""}.fa-list:before{content:""}.fa-dedent:before,.fa-outdent:before{content:""}.fa-indent:before{content:""}.fa-video-camera:before{content:""}.fa-image:before,.fa-photo:before,.fa-picture-o:before{content:""}.fa-pencil:before{content:""}.fa-map-marker:before{content:""}.fa-adjust:before{content:""}.fa-tint:before{content:""}.fa-edit:before,.fa-pencil-square-o:before{content:""}.fa-share-square-o:before{content:""}.fa-check-square-o:before{content:""}.fa-arrows:before{content:""}.fa-step-backward:before{content:""}.fa-fast-backward:before{content:""}.fa-backward:before{content:""}.fa-play:before{content:""}.fa-pause:before{content:""}.fa-stop:before{content:""}.fa-forward:before{content:""}.fa-fast-forward:before{content:""}.fa-step-forward:before{content:""}.fa-eject:before{content:""}.fa-chevron-left:before{content:""}.fa-chevron-right:before{content:""}.fa-plus-circle:before{content:""}.fa-minus-circle:before{content:""}.fa-times-circle:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before{content:""}.fa-check-circle:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before{content:""}.fa-question-circle:before{content:""}.fa-info-circle:before{content:""}.fa-crosshairs:before{content:""}.fa-times-circle-o:before{content:""}.fa-check-circle-o:before{content:""}.fa-ban:before{content:""}.fa-arrow-left:before{content:""}.fa-arrow-right:before{content:""}.fa-arrow-up:before{content:""}.fa-arrow-down:before{content:""}.fa-mail-forward:before,.fa-share:before{content:""}.fa-expand:before{content:""}.fa-compress:before{content:""}.fa-plus:before{content:""}.fa-minus:before{content:""}.fa-asterisk:before{content:""}.fa-exclamation-circle:before,.rst-content .admonition-title:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before{content:""}.fa-gift:before{content:""}.fa-leaf:before{content:""}.fa-fire:before,.icon-fire:before{content:""}.fa-eye:before{content:""}.fa-eye-slash:before{content:""}.fa-exclamation-triangle:before,.fa-warning:before{content:""}.fa-plane:before{content:""}.fa-calendar:before{content:""}.fa-random:before{content:""}.fa-comment:before{content:""}.fa-magnet:before{content:""}.fa-chevron-up:before{content:""}.fa-chevron-down:before{content:""}.fa-retweet:before{content:""}.fa-shopping-cart:before{content:""}.fa-folder:before{content:""}.fa-folder-open:before{content:""}.fa-arrows-v:before{content:""}.fa-arrows-h:before{content:""}.fa-bar-chart-o:before,.fa-bar-chart:before{content:""}.fa-twitter-square:before{content:""}.fa-facebook-square:before{content:""}.fa-camera-retro:before{content:""}.fa-key:before{content:""}.fa-cogs:before,.fa-gears:before{content:""}.fa-comments:before{content:""}.fa-thumbs-o-up:before{content:""}.fa-thumbs-o-down:before{content:""}.fa-star-half:before{content:""}.fa-heart-o:before{content:""}.fa-sign-out:before{content:""}.fa-linkedin-square:before{content:""}.fa-thumb-tack:before{content:""}.fa-external-link:before{content:""}.fa-sign-in:before{content:""}.fa-trophy:before{content:""}.fa-github-square:before{content:""}.fa-upload:before{content:""}.fa-lemon-o:before{content:""}.fa-phone:before{content:""}.fa-square-o:before{content:""}.fa-bookmark-o:before{content:""}.fa-phone-square:before{content:""}.fa-twitter:before{content:""}.fa-facebook-f:before,.fa-facebook:before{content:""}.fa-github:before,.icon-github:before{content:""}.fa-unlock:before{content:""}.fa-credit-card:before{content:""}.fa-feed:before,.fa-rss:before{content:""}.fa-hdd-o:before{content:""}.fa-bullhorn:before{content:""}.fa-bell:before{content:""}.fa-certificate:before{content:""}.fa-hand-o-right:before{content:""}.fa-hand-o-left:before{content:""}.fa-hand-o-up:before{content:""}.fa-hand-o-down:before{content:""}.fa-arrow-circle-left:before,.icon-circle-arrow-left:before{content:""}.fa-arrow-circle-right:before,.icon-circle-arrow-right:before{content:""}.fa-arrow-circle-up:before{content:""}.fa-arrow-circle-down:before{content:""}.fa-globe:before{content:""}.fa-wrench:before{content:""}.fa-tasks:before{content:""}.fa-filter:before{content:""}.fa-briefcase:before{content:""}.fa-arrows-alt:before{content:""}.fa-group:before,.fa-users:before{content:""}.fa-chain:before,.fa-link:before,.icon-link:before{content:""}.fa-cloud:before{content:""}.fa-flask:before{content:""}.fa-cut:before,.fa-scissors:before{content:""}.fa-copy:before,.fa-files-o:before{content:""}.fa-paperclip:before{content:""}.fa-floppy-o:before,.fa-save:before{content:""}.fa-square:before{content:""}.fa-bars:before,.fa-navicon:before,.fa-reorder:before{content:""}.fa-list-ul:before{content:""}.fa-list-ol:before{content:""}.fa-strikethrough:before{content:""}.fa-underline:before{content:""}.fa-table:before{content:""}.fa-magic:before{content:""}.fa-truck:before{content:""}.fa-pinterest:before{content:""}.fa-pinterest-square:before{content:""}.fa-google-plus-square:before{content:""}.fa-google-plus:before{content:""}.fa-money:before{content:""}.fa-caret-down:before,.icon-caret-down:before,.wy-dropdown .caret:before{content:""}.fa-caret-up:before{content:""}.fa-caret-left:before{content:""}.fa-caret-right:before{content:""}.fa-columns:before{content:""}.fa-sort:before,.fa-unsorted:before{content:""}.fa-sort-desc:before,.fa-sort-down:before{content:""}.fa-sort-asc:before,.fa-sort-up:before{content:""}.fa-envelope:before{content:""}.fa-linkedin:before{content:""}.fa-rotate-left:before,.fa-undo:before{content:""}.fa-gavel:before,.fa-legal:before{content:""}.fa-dashboard:before,.fa-tachometer:before{content:""}.fa-comment-o:before{content:""}.fa-comments-o:before{content:""}.fa-bolt:before,.fa-flash:before{content:""}.fa-sitemap:before{content:""}.fa-umbrella:before{content:""}.fa-clipboard:before,.fa-paste:before{content:""}.fa-lightbulb-o:before{content:""}.fa-exchange:before{content:""}.fa-cloud-download:before{content:""}.fa-cloud-upload:before{content:""}.fa-user-md:before{content:""}.fa-stethoscope:before{content:""}.fa-suitcase:before{content:""}.fa-bell-o:before{content:""}.fa-coffee:before{content:""}.fa-cutlery:before{content:""}.fa-file-text-o:before{content:""}.fa-building-o:before{content:""}.fa-hospital-o:before{content:""}.fa-ambulance:before{content:""}.fa-medkit:before{content:""}.fa-fighter-jet:before{content:""}.fa-beer:before{content:""}.fa-h-square:before{content:""}.fa-plus-square:before{content:""}.fa-angle-double-left:before{content:""}.fa-angle-double-right:before{content:""}.fa-angle-double-up:before{content:""}.fa-angle-double-down:before{content:""}.fa-angle-left:before{content:""}.fa-angle-right:before{content:""}.fa-angle-up:before{content:""}.fa-angle-down:before{content:""}.fa-desktop:before{content:""}.fa-laptop:before{content:""}.fa-tablet:before{content:""}.fa-mobile-phone:before,.fa-mobile:before{content:""}.fa-circle-o:before{content:""}.fa-quote-left:before{content:""}.fa-quote-right:before{content:""}.fa-spinner:before{content:""}.fa-circle:before{content:""}.fa-mail-reply:before,.fa-reply:before{content:""}.fa-github-alt:before{content:""}.fa-folder-o:before{content:""}.fa-folder-open-o:before{content:""}.fa-smile-o:before{content:""}.fa-frown-o:before{content:""}.fa-meh-o:before{content:""}.fa-gamepad:before{content:""}.fa-keyboard-o:before{content:""}.fa-flag-o:before{content:""}.fa-flag-checkered:before{content:""}.fa-terminal:before{content:""}.fa-code:before{content:""}.fa-mail-reply-all:before,.fa-reply-all:before{content:""}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:""}.fa-location-arrow:before{content:""}.fa-crop:before{content:""}.fa-code-fork:before{content:""}.fa-chain-broken:before,.fa-unlink:before{content:""}.fa-question:before{content:""}.fa-info:before{content:""}.fa-exclamation:before{content:""}.fa-superscript:before{content:""}.fa-subscript:before{content:""}.fa-eraser:before{content:""}.fa-puzzle-piece:before{content:""}.fa-microphone:before{content:""}.fa-microphone-slash:before{content:""}.fa-shield:before{content:""}.fa-calendar-o:before{content:""}.fa-fire-extinguisher:before{content:""}.fa-rocket:before{content:""}.fa-maxcdn:before{content:""}.fa-chevron-circle-left:before{content:""}.fa-chevron-circle-right:before{content:""}.fa-chevron-circle-up:before{content:""}.fa-chevron-circle-down:before{content:""}.fa-html5:before{content:""}.fa-css3:before{content:""}.fa-anchor:before{content:""}.fa-unlock-alt:before{content:""}.fa-bullseye:before{content:""}.fa-ellipsis-h:before{content:""}.fa-ellipsis-v:before{content:""}.fa-rss-square:before{content:""}.fa-play-circle:before{content:""}.fa-ticket:before{content:""}.fa-minus-square:before{content:""}.fa-minus-square-o:before,.wy-menu-vertical li.current>a button.toctree-expand:before,.wy-menu-vertical li.on a button.toctree-expand:before{content:""}.fa-level-up:before{content:""}.fa-level-down:before{content:""}.fa-check-square:before{content:""}.fa-pencil-square:before{content:""}.fa-external-link-square:before{content:""}.fa-share-square:before{content:""}.fa-compass:before{content:""}.fa-caret-square-o-down:before,.fa-toggle-down:before{content:""}.fa-caret-square-o-up:before,.fa-toggle-up:before{content:""}.fa-caret-square-o-right:before,.fa-toggle-right:before{content:""}.fa-eur:before,.fa-euro:before{content:""}.fa-gbp:before{content:""}.fa-dollar:before,.fa-usd:before{content:""}.fa-inr:before,.fa-rupee:before{content:""}.fa-cny:before,.fa-jpy:before,.fa-rmb:before,.fa-yen:before{content:""}.fa-rouble:before,.fa-rub:before,.fa-ruble:before{content:""}.fa-krw:before,.fa-won:before{content:""}.fa-bitcoin:before,.fa-btc:before{content:""}.fa-file:before{content:""}.fa-file-text:before{content:""}.fa-sort-alpha-asc:before{content:""}.fa-sort-alpha-desc:before{content:""}.fa-sort-amount-asc:before{content:""}.fa-sort-amount-desc:before{content:""}.fa-sort-numeric-asc:before{content:""}.fa-sort-numeric-desc:before{content:""}.fa-thumbs-up:before{content:""}.fa-thumbs-down:before{content:""}.fa-youtube-square:before{content:""}.fa-youtube:before{content:""}.fa-xing:before{content:""}.fa-xing-square:before{content:""}.fa-youtube-play:before{content:""}.fa-dropbox:before{content:""}.fa-stack-overflow:before{content:""}.fa-instagram:before{content:""}.fa-flickr:before{content:""}.fa-adn:before{content:""}.fa-bitbucket:before,.icon-bitbucket:before{content:""}.fa-bitbucket-square:before{content:""}.fa-tumblr:before{content:""}.fa-tumblr-square:before{content:""}.fa-long-arrow-down:before{content:""}.fa-long-arrow-up:before{content:""}.fa-long-arrow-left:before{content:""}.fa-long-arrow-right:before{content:""}.fa-apple:before{content:""}.fa-windows:before{content:""}.fa-android:before{content:""}.fa-linux:before{content:""}.fa-dribbble:before{content:""}.fa-skype:before{content:""}.fa-foursquare:before{content:""}.fa-trello:before{content:""}.fa-female:before{content:""}.fa-male:before{content:""}.fa-gittip:before,.fa-gratipay:before{content:""}.fa-sun-o:before{content:""}.fa-moon-o:before{content:""}.fa-archive:before{content:""}.fa-bug:before{content:""}.fa-vk:before{content:""}.fa-weibo:before{content:""}.fa-renren:before{content:""}.fa-pagelines:before{content:""}.fa-stack-exchange:before{content:""}.fa-arrow-circle-o-right:before{content:""}.fa-arrow-circle-o-left:before{content:""}.fa-caret-square-o-left:before,.fa-toggle-left:before{content:""}.fa-dot-circle-o:before{content:""}.fa-wheelchair:before{content:""}.fa-vimeo-square:before{content:""}.fa-try:before,.fa-turkish-lira:before{content:""}.fa-plus-square-o:before,.wy-menu-vertical li button.toctree-expand:before{content:""}.fa-space-shuttle:before{content:""}.fa-slack:before{content:""}.fa-envelope-square:before{content:""}.fa-wordpress:before{content:""}.fa-openid:before{content:""}.fa-bank:before,.fa-institution:before,.fa-university:before{content:""}.fa-graduation-cap:before,.fa-mortar-board:before{content:""}.fa-yahoo:before{content:""}.fa-google:before{content:""}.fa-reddit:before{content:""}.fa-reddit-square:before{content:""}.fa-stumbleupon-circle:before{content:""}.fa-stumbleupon:before{content:""}.fa-delicious:before{content:""}.fa-digg:before{content:""}.fa-pied-piper-pp:before{content:""}.fa-pied-piper-alt:before{content:""}.fa-drupal:before{content:""}.fa-joomla:before{content:""}.fa-language:before{content:""}.fa-fax:before{content:""}.fa-building:before{content:""}.fa-child:before{content:""}.fa-paw:before{content:""}.fa-spoon:before{content:""}.fa-cube:before{content:""}.fa-cubes:before{content:""}.fa-behance:before{content:""}.fa-behance-square:before{content:""}.fa-steam:before{content:""}.fa-steam-square:before{content:""}.fa-recycle:before{content:""}.fa-automobile:before,.fa-car:before{content:""}.fa-cab:before,.fa-taxi:before{content:""}.fa-tree:before{content:""}.fa-spotify:before{content:""}.fa-deviantart:before{content:""}.fa-soundcloud:before{content:""}.fa-database:before{content:""}.fa-file-pdf-o:before{content:""}.fa-file-word-o:before{content:""}.fa-file-excel-o:before{content:""}.fa-file-powerpoint-o:before{content:""}.fa-file-image-o:before,.fa-file-photo-o:before,.fa-file-picture-o:before{content:""}.fa-file-archive-o:before,.fa-file-zip-o:before{content:""}.fa-file-audio-o:before,.fa-file-sound-o:before{content:""}.fa-file-movie-o:before,.fa-file-video-o:before{content:""}.fa-file-code-o:before{content:""}.fa-vine:before{content:""}.fa-codepen:before{content:""}.fa-jsfiddle:before{content:""}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-ring:before,.fa-life-saver:before,.fa-support:before{content:""}.fa-circle-o-notch:before{content:""}.fa-ra:before,.fa-rebel:before,.fa-resistance:before{content:""}.fa-empire:before,.fa-ge:before{content:""}.fa-git-square:before{content:""}.fa-git:before{content:""}.fa-hacker-news:before,.fa-y-combinator-square:before,.fa-yc-square:before{content:""}.fa-tencent-weibo:before{content:""}.fa-qq:before{content:""}.fa-wechat:before,.fa-weixin:before{content:""}.fa-paper-plane:before,.fa-send:before{content:""}.fa-paper-plane-o:before,.fa-send-o:before{content:""}.fa-history:before{content:""}.fa-circle-thin:before{content:""}.fa-header:before{content:""}.fa-paragraph:before{content:""}.fa-sliders:before{content:""}.fa-share-alt:before{content:""}.fa-share-alt-square:before{content:""}.fa-bomb:before{content:""}.fa-futbol-o:before,.fa-soccer-ball-o:before{content:""}.fa-tty:before{content:""}.fa-binoculars:before{content:""}.fa-plug:before{content:""}.fa-slideshare:before{content:""}.fa-twitch:before{content:""}.fa-yelp:before{content:""}.fa-newspaper-o:before{content:""}.fa-wifi:before{content:""}.fa-calculator:before{content:""}.fa-paypal:before{content:""}.fa-google-wallet:before{content:""}.fa-cc-visa:before{content:""}.fa-cc-mastercard:before{content:""}.fa-cc-discover:before{content:""}.fa-cc-amex:before{content:""}.fa-cc-paypal:before{content:""}.fa-cc-stripe:before{content:""}.fa-bell-slash:before{content:""}.fa-bell-slash-o:before{content:""}.fa-trash:before{content:""}.fa-copyright:before{content:""}.fa-at:before{content:""}.fa-eyedropper:before{content:""}.fa-paint-brush:before{content:""}.fa-birthday-cake:before{content:""}.fa-area-chart:before{content:""}.fa-pie-chart:before{content:""}.fa-line-chart:before{content:""}.fa-lastfm:before{content:""}.fa-lastfm-square:before{content:""}.fa-toggle-off:before{content:""}.fa-toggle-on:before{content:""}.fa-bicycle:before{content:""}.fa-bus:before{content:""}.fa-ioxhost:before{content:""}.fa-angellist:before{content:""}.fa-cc:before{content:""}.fa-ils:before,.fa-shekel:before,.fa-sheqel:before{content:""}.fa-meanpath:before{content:""}.fa-buysellads:before{content:""}.fa-connectdevelop:before{content:""}.fa-dashcube:before{content:""}.fa-forumbee:before{content:""}.fa-leanpub:before{content:""}.fa-sellsy:before{content:""}.fa-shirtsinbulk:before{content:""}.fa-simplybuilt:before{content:""}.fa-skyatlas:before{content:""}.fa-cart-plus:before{content:""}.fa-cart-arrow-down:before{content:""}.fa-diamond:before{content:""}.fa-ship:before{content:""}.fa-user-secret:before{content:""}.fa-motorcycle:before{content:""}.fa-street-view:before{content:""}.fa-heartbeat:before{content:""}.fa-venus:before{content:""}.fa-mars:before{content:""}.fa-mercury:before{content:""}.fa-intersex:before,.fa-transgender:before{content:""}.fa-transgender-alt:before{content:""}.fa-venus-double:before{content:""}.fa-mars-double:before{content:""}.fa-venus-mars:before{content:""}.fa-mars-stroke:before{content:""}.fa-mars-stroke-v:before{content:""}.fa-mars-stroke-h:before{content:""}.fa-neuter:before{content:""}.fa-genderless:before{content:""}.fa-facebook-official:before{content:""}.fa-pinterest-p:before{content:""}.fa-whatsapp:before{content:""}.fa-server:before{content:""}.fa-user-plus:before{content:""}.fa-user-times:before{content:""}.fa-bed:before,.fa-hotel:before{content:""}.fa-viacoin:before{content:""}.fa-train:before{content:""}.fa-subway:before{content:""}.fa-medium:before{content:""}.fa-y-combinator:before,.fa-yc:before{content:""}.fa-optin-monster:before{content:""}.fa-opencart:before{content:""}.fa-expeditedssl:before{content:""}.fa-battery-4:before,.fa-battery-full:before,.fa-battery:before{content:""}.fa-battery-3:before,.fa-battery-three-quarters:before{content:""}.fa-battery-2:before,.fa-battery-half:before{content:""}.fa-battery-1:before,.fa-battery-quarter:before{content:""}.fa-battery-0:before,.fa-battery-empty:before{content:""}.fa-mouse-pointer:before{content:""}.fa-i-cursor:before{content:""}.fa-object-group:before{content:""}.fa-object-ungroup:before{content:""}.fa-sticky-note:before{content:""}.fa-sticky-note-o:before{content:""}.fa-cc-jcb:before{content:""}.fa-cc-diners-club:before{content:""}.fa-clone:before{content:""}.fa-balance-scale:before{content:""}.fa-hourglass-o:before{content:""}.fa-hourglass-1:before,.fa-hourglass-start:before{content:""}.fa-hourglass-2:before,.fa-hourglass-half:before{content:""}.fa-hourglass-3:before,.fa-hourglass-end:before{content:""}.fa-hourglass:before{content:""}.fa-hand-grab-o:before,.fa-hand-rock-o:before{content:""}.fa-hand-paper-o:before,.fa-hand-stop-o:before{content:""}.fa-hand-scissors-o:before{content:""}.fa-hand-lizard-o:before{content:""}.fa-hand-spock-o:before{content:""}.fa-hand-pointer-o:before{content:""}.fa-hand-peace-o:before{content:""}.fa-trademark:before{content:""}.fa-registered:before{content:""}.fa-creative-commons:before{content:""}.fa-gg:before{content:""}.fa-gg-circle:before{content:""}.fa-tripadvisor:before{content:""}.fa-odnoklassniki:before{content:""}.fa-odnoklassniki-square:before{content:""}.fa-get-pocket:before{content:""}.fa-wikipedia-w:before{content:""}.fa-safari:before{content:""}.fa-chrome:before{content:""}.fa-firefox:before{content:""}.fa-opera:before{content:""}.fa-internet-explorer:before{content:""}.fa-television:before,.fa-tv:before{content:""}.fa-contao:before{content:""}.fa-500px:before{content:""}.fa-amazon:before{content:""}.fa-calendar-plus-o:before{content:""}.fa-calendar-minus-o:before{content:""}.fa-calendar-times-o:before{content:""}.fa-calendar-check-o:before{content:""}.fa-industry:before{content:""}.fa-map-pin:before{content:""}.fa-map-signs:before{content:""}.fa-map-o:before{content:""}.fa-map:before{content:""}.fa-commenting:before{content:""}.fa-commenting-o:before{content:""}.fa-houzz:before{content:""}.fa-vimeo:before{content:""}.fa-black-tie:before{content:""}.fa-fonticons:before{content:""}.fa-reddit-alien:before{content:""}.fa-edge:before{content:""}.fa-credit-card-alt:before{content:""}.fa-codiepie:before{content:""}.fa-modx:before{content:""}.fa-fort-awesome:before{content:""}.fa-usb:before{content:""}.fa-product-hunt:before{content:""}.fa-mixcloud:before{content:""}.fa-scribd:before{content:""}.fa-pause-circle:before{content:""}.fa-pause-circle-o:before{content:""}.fa-stop-circle:before{content:""}.fa-stop-circle-o:before{content:""}.fa-shopping-bag:before{content:""}.fa-shopping-basket:before{content:""}.fa-hashtag:before{content:""}.fa-bluetooth:before{content:""}.fa-bluetooth-b:before{content:""}.fa-percent:before{content:""}.fa-gitlab:before,.icon-gitlab:before{content:""}.fa-wpbeginner:before{content:""}.fa-wpforms:before{content:""}.fa-envira:before{content:""}.fa-universal-access:before{content:""}.fa-wheelchair-alt:before{content:""}.fa-question-circle-o:before{content:""}.fa-blind:before{content:""}.fa-audio-description:before{content:""}.fa-volume-control-phone:before{content:""}.fa-braille:before{content:""}.fa-assistive-listening-systems:before{content:""}.fa-american-sign-language-interpreting:before,.fa-asl-interpreting:before{content:""}.fa-deaf:before,.fa-deafness:before,.fa-hard-of-hearing:before{content:""}.fa-glide:before{content:""}.fa-glide-g:before{content:""}.fa-sign-language:before,.fa-signing:before{content:""}.fa-low-vision:before{content:""}.fa-viadeo:before{content:""}.fa-viadeo-square:before{content:""}.fa-snapchat:before{content:""}.fa-snapchat-ghost:before{content:""}.fa-snapchat-square:before{content:""}.fa-pied-piper:before{content:""}.fa-first-order:before{content:""}.fa-yoast:before{content:""}.fa-themeisle:before{content:""}.fa-google-plus-circle:before,.fa-google-plus-official:before{content:""}.fa-fa:before,.fa-font-awesome:before{content:""}.fa-handshake-o:before{content:""}.fa-envelope-open:before{content:""}.fa-envelope-open-o:before{content:""}.fa-linode:before{content:""}.fa-address-book:before{content:""}.fa-address-book-o:before{content:""}.fa-address-card:before,.fa-vcard:before{content:""}.fa-address-card-o:before,.fa-vcard-o:before{content:""}.fa-user-circle:before{content:""}.fa-user-circle-o:before{content:""}.fa-user-o:before{content:""}.fa-id-badge:before{content:""}.fa-drivers-license:before,.fa-id-card:before{content:""}.fa-drivers-license-o:before,.fa-id-card-o:before{content:""}.fa-quora:before{content:""}.fa-free-code-camp:before{content:""}.fa-telegram:before{content:""}.fa-thermometer-4:before,.fa-thermometer-full:before,.fa-thermometer:before{content:""}.fa-thermometer-3:before,.fa-thermometer-three-quarters:before{content:""}.fa-thermometer-2:before,.fa-thermometer-half:before{content:""}.fa-thermometer-1:before,.fa-thermometer-quarter:before{content:""}.fa-thermometer-0:before,.fa-thermometer-empty:before{content:""}.fa-shower:before{content:""}.fa-bath:before,.fa-bathtub:before,.fa-s15:before{content:""}.fa-podcast:before{content:""}.fa-window-maximize:before{content:""}.fa-window-minimize:before{content:""}.fa-window-restore:before{content:""}.fa-times-rectangle:before,.fa-window-close:before{content:""}.fa-times-rectangle-o:before,.fa-window-close-o:before{content:""}.fa-bandcamp:before{content:""}.fa-grav:before{content:""}.fa-etsy:before{content:""}.fa-imdb:before{content:""}.fa-ravelry:before{content:""}.fa-eercast:before{content:""}.fa-microchip:before{content:""}.fa-snowflake-o:before{content:""}.fa-superpowers:before{content:""}.fa-wpexplorer:before{content:""}.fa-meetup:before{content:""}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}.fa,.icon,.rst-content .admonition-title,.rst-content .code-block-caption .headerlink,.rst-content .eqno .headerlink,.rst-content code.download span:first-child,.rst-content dl dt .headerlink,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content p.caption .headerlink,.rst-content p .headerlink,.rst-content table>caption .headerlink,.rst-content tt.download span:first-child,.wy-dropdown .caret,.wy-inline-validate.wy-inline-validate-danger .wy-input-context,.wy-inline-validate.wy-inline-validate-info .wy-input-context,.wy-inline-validate.wy-inline-validate-success .wy-input-context,.wy-inline-validate.wy-inline-validate-warning .wy-input-context,.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand,.wy-menu-vertical li button.toctree-expand{font-family:inherit}.fa:before,.icon:before,.rst-content .admonition-title:before,.rst-content .code-block-caption .headerlink:before,.rst-content .eqno .headerlink:before,.rst-content code.download span:first-child:before,.rst-content dl dt .headerlink:before,.rst-content h1 .headerlink:before,.rst-content h2 .headerlink:before,.rst-content h3 .headerlink:before,.rst-content h4 .headerlink:before,.rst-content h5 .headerlink:before,.rst-content h6 .headerlink:before,.rst-content p.caption .headerlink:before,.rst-content p .headerlink:before,.rst-content table>caption .headerlink:before,.rst-content tt.download span:first-child:before,.wy-dropdown .caret:before,.wy-inline-validate.wy-inline-validate-danger .wy-input-context:before,.wy-inline-validate.wy-inline-validate-info .wy-input-context:before,.wy-inline-validate.wy-inline-validate-success .wy-input-context:before,.wy-inline-validate.wy-inline-validate-warning .wy-input-context:before,.wy-menu-vertical li.current>a button.toctree-expand:before,.wy-menu-vertical li.on a button.toctree-expand:before,.wy-menu-vertical li button.toctree-expand:before{font-family:FontAwesome;display:inline-block;font-style:normal;font-weight:400;line-height:1;text-decoration:inherit}.rst-content .code-block-caption a .headerlink,.rst-content .eqno a .headerlink,.rst-content a .admonition-title,.rst-content code.download a span:first-child,.rst-content dl dt a .headerlink,.rst-content h1 a .headerlink,.rst-content h2 a .headerlink,.rst-content h3 a .headerlink,.rst-content h4 a .headerlink,.rst-content h5 a .headerlink,.rst-content h6 a .headerlink,.rst-content p.caption a .headerlink,.rst-content p a .headerlink,.rst-content table>caption a .headerlink,.rst-content tt.download a span:first-child,.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand,.wy-menu-vertical li a button.toctree-expand,a .fa,a .icon,a .rst-content .admonition-title,a .rst-content .code-block-caption .headerlink,a .rst-content .eqno .headerlink,a .rst-content code.download span:first-child,a .rst-content dl dt .headerlink,a .rst-content h1 .headerlink,a .rst-content h2 .headerlink,a .rst-content h3 .headerlink,a .rst-content h4 .headerlink,a .rst-content h5 .headerlink,a .rst-content h6 .headerlink,a .rst-content p.caption .headerlink,a .rst-content p .headerlink,a .rst-content table>caption .headerlink,a .rst-content tt.download span:first-child,a .wy-menu-vertical li button.toctree-expand{display:inline-block;text-decoration:inherit}.btn .fa,.btn .icon,.btn .rst-content .admonition-title,.btn .rst-content .code-block-caption .headerlink,.btn .rst-content .eqno .headerlink,.btn .rst-content code.download span:first-child,.btn .rst-content dl dt .headerlink,.btn .rst-content h1 .headerlink,.btn .rst-content h2 .headerlink,.btn .rst-content h3 .headerlink,.btn .rst-content h4 .headerlink,.btn .rst-content h5 .headerlink,.btn .rst-content h6 .headerlink,.btn .rst-content p .headerlink,.btn .rst-content table>caption .headerlink,.btn .rst-content tt.download span:first-child,.btn .wy-menu-vertical li.current>a button.toctree-expand,.btn .wy-menu-vertical li.on a button.toctree-expand,.btn .wy-menu-vertical li button.toctree-expand,.nav .fa,.nav .icon,.nav .rst-content .admonition-title,.nav .rst-content .code-block-caption .headerlink,.nav .rst-content .eqno .headerlink,.nav .rst-content code.download span:first-child,.nav .rst-content dl dt .headerlink,.nav .rst-content h1 .headerlink,.nav .rst-content h2 .headerlink,.nav .rst-content h3 .headerlink,.nav .rst-content h4 .headerlink,.nav .rst-content h5 .headerlink,.nav .rst-content h6 .headerlink,.nav .rst-content p .headerlink,.nav .rst-content table>caption .headerlink,.nav .rst-content tt.download span:first-child,.nav .wy-menu-vertical li.current>a button.toctree-expand,.nav .wy-menu-vertical li.on a button.toctree-expand,.nav .wy-menu-vertical li button.toctree-expand,.rst-content .btn .admonition-title,.rst-content .code-block-caption .btn .headerlink,.rst-content .code-block-caption .nav .headerlink,.rst-content .eqno .btn .headerlink,.rst-content .eqno .nav .headerlink,.rst-content .nav .admonition-title,.rst-content code.download .btn span:first-child,.rst-content code.download .nav span:first-child,.rst-content dl dt .btn .headerlink,.rst-content dl dt .nav .headerlink,.rst-content h1 .btn .headerlink,.rst-content h1 .nav .headerlink,.rst-content h2 .btn .headerlink,.rst-content h2 .nav .headerlink,.rst-content h3 .btn .headerlink,.rst-content h3 .nav .headerlink,.rst-content h4 .btn .headerlink,.rst-content h4 .nav .headerlink,.rst-content h5 .btn .headerlink,.rst-content h5 .nav .headerlink,.rst-content h6 .btn .headerlink,.rst-content h6 .nav .headerlink,.rst-content p .btn .headerlink,.rst-content p .nav .headerlink,.rst-content table>caption .btn .headerlink,.rst-content table>caption .nav .headerlink,.rst-content tt.download .btn span:first-child,.rst-content tt.download .nav span:first-child,.wy-menu-vertical li .btn button.toctree-expand,.wy-menu-vertical li.current>a .btn button.toctree-expand,.wy-menu-vertical li.current>a .nav button.toctree-expand,.wy-menu-vertical li .nav button.toctree-expand,.wy-menu-vertical li.on a .btn button.toctree-expand,.wy-menu-vertical li.on a .nav button.toctree-expand{display:inline}.btn .fa-large.icon,.btn .fa.fa-large,.btn .rst-content .code-block-caption .fa-large.headerlink,.btn .rst-content .eqno .fa-large.headerlink,.btn .rst-content .fa-large.admonition-title,.btn .rst-content code.download span.fa-large:first-child,.btn .rst-content dl dt .fa-large.headerlink,.btn .rst-content h1 .fa-large.headerlink,.btn .rst-content h2 .fa-large.headerlink,.btn .rst-content h3 .fa-large.headerlink,.btn .rst-content h4 .fa-large.headerlink,.btn .rst-content h5 .fa-large.headerlink,.btn .rst-content h6 .fa-large.headerlink,.btn .rst-content p .fa-large.headerlink,.btn .rst-content table>caption .fa-large.headerlink,.btn .rst-content tt.download span.fa-large:first-child,.btn .wy-menu-vertical li button.fa-large.toctree-expand,.nav .fa-large.icon,.nav .fa.fa-large,.nav .rst-content .code-block-caption .fa-large.headerlink,.nav .rst-content .eqno .fa-large.headerlink,.nav .rst-content .fa-large.admonition-title,.nav .rst-content code.download span.fa-large:first-child,.nav .rst-content dl dt .fa-large.headerlink,.nav .rst-content h1 .fa-large.headerlink,.nav .rst-content h2 .fa-large.headerlink,.nav .rst-content h3 .fa-large.headerlink,.nav .rst-content h4 .fa-large.headerlink,.nav .rst-content h5 .fa-large.headerlink,.nav .rst-content h6 .fa-large.headerlink,.nav .rst-content p .fa-large.headerlink,.nav .rst-content table>caption .fa-large.headerlink,.nav .rst-content tt.download span.fa-large:first-child,.nav .wy-menu-vertical li button.fa-large.toctree-expand,.rst-content .btn .fa-large.admonition-title,.rst-content .code-block-caption .btn .fa-large.headerlink,.rst-content .code-block-caption .nav .fa-large.headerlink,.rst-content .eqno .btn .fa-large.headerlink,.rst-content .eqno .nav .fa-large.headerlink,.rst-content .nav .fa-large.admonition-title,.rst-content code.download .btn span.fa-large:first-child,.rst-content code.download .nav span.fa-large:first-child,.rst-content dl dt .btn .fa-large.headerlink,.rst-content dl dt .nav .fa-large.headerlink,.rst-content h1 .btn .fa-large.headerlink,.rst-content h1 .nav .fa-large.headerlink,.rst-content h2 .btn .fa-large.headerlink,.rst-content h2 .nav .fa-large.headerlink,.rst-content h3 .btn .fa-large.headerlink,.rst-content h3 .nav .fa-large.headerlink,.rst-content h4 .btn .fa-large.headerlink,.rst-content h4 .nav .fa-large.headerlink,.rst-content h5 .btn .fa-large.headerlink,.rst-content h5 .nav .fa-large.headerlink,.rst-content h6 .btn .fa-large.headerlink,.rst-content h6 .nav .fa-large.headerlink,.rst-content p .btn .fa-large.headerlink,.rst-content p .nav .fa-large.headerlink,.rst-content table>caption .btn .fa-large.headerlink,.rst-content table>caption .nav .fa-large.headerlink,.rst-content tt.download .btn span.fa-large:first-child,.rst-content tt.download .nav span.fa-large:first-child,.wy-menu-vertical li .btn button.fa-large.toctree-expand,.wy-menu-vertical li .nav button.fa-large.toctree-expand{line-height:.9em}.btn .fa-spin.icon,.btn .fa.fa-spin,.btn .rst-content .code-block-caption .fa-spin.headerlink,.btn .rst-content .eqno .fa-spin.headerlink,.btn .rst-content .fa-spin.admonition-title,.btn .rst-content code.download span.fa-spin:first-child,.btn .rst-content dl dt .fa-spin.headerlink,.btn .rst-content h1 .fa-spin.headerlink,.btn .rst-content h2 .fa-spin.headerlink,.btn .rst-content h3 .fa-spin.headerlink,.btn .rst-content h4 .fa-spin.headerlink,.btn .rst-content h5 .fa-spin.headerlink,.btn .rst-content h6 .fa-spin.headerlink,.btn .rst-content p .fa-spin.headerlink,.btn .rst-content table>caption .fa-spin.headerlink,.btn .rst-content tt.download span.fa-spin:first-child,.btn .wy-menu-vertical li button.fa-spin.toctree-expand,.nav .fa-spin.icon,.nav .fa.fa-spin,.nav .rst-content .code-block-caption .fa-spin.headerlink,.nav .rst-content .eqno .fa-spin.headerlink,.nav .rst-content .fa-spin.admonition-title,.nav .rst-content code.download span.fa-spin:first-child,.nav .rst-content dl dt .fa-spin.headerlink,.nav .rst-content h1 .fa-spin.headerlink,.nav .rst-content h2 .fa-spin.headerlink,.nav .rst-content h3 .fa-spin.headerlink,.nav .rst-content h4 .fa-spin.headerlink,.nav .rst-content h5 .fa-spin.headerlink,.nav .rst-content h6 .fa-spin.headerlink,.nav .rst-content p .fa-spin.headerlink,.nav .rst-content table>caption .fa-spin.headerlink,.nav .rst-content tt.download span.fa-spin:first-child,.nav .wy-menu-vertical li button.fa-spin.toctree-expand,.rst-content .btn .fa-spin.admonition-title,.rst-content .code-block-caption .btn .fa-spin.headerlink,.rst-content .code-block-caption .nav .fa-spin.headerlink,.rst-content .eqno .btn .fa-spin.headerlink,.rst-content .eqno .nav .fa-spin.headerlink,.rst-content .nav .fa-spin.admonition-title,.rst-content code.download .btn span.fa-spin:first-child,.rst-content code.download .nav span.fa-spin:first-child,.rst-content dl dt .btn .fa-spin.headerlink,.rst-content dl dt .nav .fa-spin.headerlink,.rst-content h1 .btn .fa-spin.headerlink,.rst-content h1 .nav .fa-spin.headerlink,.rst-content h2 .btn .fa-spin.headerlink,.rst-content h2 .nav .fa-spin.headerlink,.rst-content h3 .btn .fa-spin.headerlink,.rst-content h3 .nav .fa-spin.headerlink,.rst-content h4 .btn .fa-spin.headerlink,.rst-content h4 .nav .fa-spin.headerlink,.rst-content h5 .btn .fa-spin.headerlink,.rst-content h5 .nav .fa-spin.headerlink,.rst-content h6 .btn .fa-spin.headerlink,.rst-content h6 .nav .fa-spin.headerlink,.rst-content p .btn .fa-spin.headerlink,.rst-content p .nav .fa-spin.headerlink,.rst-content table>caption .btn .fa-spin.headerlink,.rst-content table>caption .nav .fa-spin.headerlink,.rst-content tt.download .btn span.fa-spin:first-child,.rst-content tt.download .nav span.fa-spin:first-child,.wy-menu-vertical li .btn button.fa-spin.toctree-expand,.wy-menu-vertical li .nav button.fa-spin.toctree-expand{display:inline-block}.btn.fa:before,.btn.icon:before,.rst-content .btn.admonition-title:before,.rst-content .code-block-caption .btn.headerlink:before,.rst-content .eqno .btn.headerlink:before,.rst-content code.download span.btn:first-child:before,.rst-content dl dt .btn.headerlink:before,.rst-content h1 .btn.headerlink:before,.rst-content h2 .btn.headerlink:before,.rst-content h3 .btn.headerlink:before,.rst-content h4 .btn.headerlink:before,.rst-content h5 .btn.headerlink:before,.rst-content h6 .btn.headerlink:before,.rst-content p .btn.headerlink:before,.rst-content table>caption .btn.headerlink:before,.rst-content tt.download span.btn:first-child:before,.wy-menu-vertical li button.btn.toctree-expand:before{opacity:.5;-webkit-transition:opacity .05s ease-in;-moz-transition:opacity .05s ease-in;transition:opacity .05s ease-in}.btn.fa:hover:before,.btn.icon:hover:before,.rst-content .btn.admonition-title:hover:before,.rst-content .code-block-caption .btn.headerlink:hover:before,.rst-content .eqno .btn.headerlink:hover:before,.rst-content code.download span.btn:first-child:hover:before,.rst-content dl dt .btn.headerlink:hover:before,.rst-content h1 .btn.headerlink:hover:before,.rst-content h2 .btn.headerlink:hover:before,.rst-content h3 .btn.headerlink:hover:before,.rst-content h4 .btn.headerlink:hover:before,.rst-content h5 .btn.headerlink:hover:before,.rst-content h6 .btn.headerlink:hover:before,.rst-content p .btn.headerlink:hover:before,.rst-content table>caption .btn.headerlink:hover:before,.rst-content tt.download span.btn:first-child:hover:before,.wy-menu-vertical li button.btn.toctree-expand:hover:before{opacity:1}.btn-mini .fa:before,.btn-mini .icon:before,.btn-mini .rst-content .admonition-title:before,.btn-mini .rst-content .code-block-caption .headerlink:before,.btn-mini .rst-content .eqno .headerlink:before,.btn-mini .rst-content code.download span:first-child:before,.btn-mini .rst-content dl dt .headerlink:before,.btn-mini .rst-content h1 .headerlink:before,.btn-mini .rst-content h2 .headerlink:before,.btn-mini .rst-content h3 .headerlink:before,.btn-mini .rst-content h4 .headerlink:before,.btn-mini .rst-content h5 .headerlink:before,.btn-mini .rst-content h6 .headerlink:before,.btn-mini .rst-content p .headerlink:before,.btn-mini .rst-content table>caption .headerlink:before,.btn-mini .rst-content tt.download span:first-child:before,.btn-mini .wy-menu-vertical li button.toctree-expand:before,.rst-content .btn-mini .admonition-title:before,.rst-content .code-block-caption .btn-mini .headerlink:before,.rst-content .eqno .btn-mini .headerlink:before,.rst-content code.download .btn-mini span:first-child:before,.rst-content dl dt .btn-mini .headerlink:before,.rst-content h1 .btn-mini .headerlink:before,.rst-content h2 .btn-mini .headerlink:before,.rst-content h3 .btn-mini .headerlink:before,.rst-content h4 .btn-mini .headerlink:before,.rst-content h5 .btn-mini .headerlink:before,.rst-content h6 .btn-mini .headerlink:before,.rst-content p .btn-mini .headerlink:before,.rst-content table>caption .btn-mini .headerlink:before,.rst-content tt.download .btn-mini span:first-child:before,.wy-menu-vertical li .btn-mini button.toctree-expand:before{font-size:14px;vertical-align:-15%}.rst-content .admonition,.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .danger,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .note,.rst-content .seealso,.rst-content .tip,.rst-content .warning,.wy-alert{padding:12px;line-height:24px;margin-bottom:24px;background:#e7f2fa}.rst-content .admonition-title,.wy-alert-title{font-weight:700;display:block;color:#fff;background:#6ab0de;padding:6px 12px;margin:-12px -12px 12px}.rst-content .danger,.rst-content .error,.rst-content .wy-alert-danger.admonition,.rst-content .wy-alert-danger.admonition-todo,.rst-content .wy-alert-danger.attention,.rst-content .wy-alert-danger.caution,.rst-content .wy-alert-danger.hint,.rst-content .wy-alert-danger.important,.rst-content .wy-alert-danger.note,.rst-content .wy-alert-danger.seealso,.rst-content .wy-alert-danger.tip,.rst-content .wy-alert-danger.warning,.wy-alert.wy-alert-danger{background:#fdf3f2}.rst-content .danger .admonition-title,.rst-content .danger .wy-alert-title,.rst-content .error .admonition-title,.rst-content .error .wy-alert-title,.rst-content .wy-alert-danger.admonition-todo .admonition-title,.rst-content .wy-alert-danger.admonition-todo .wy-alert-title,.rst-content .wy-alert-danger.admonition .admonition-title,.rst-content .wy-alert-danger.admonition .wy-alert-title,.rst-content .wy-alert-danger.attention .admonition-title,.rst-content .wy-alert-danger.attention .wy-alert-title,.rst-content .wy-alert-danger.caution .admonition-title,.rst-content .wy-alert-danger.caution .wy-alert-title,.rst-content .wy-alert-danger.hint .admonition-title,.rst-content .wy-alert-danger.hint .wy-alert-title,.rst-content .wy-alert-danger.important .admonition-title,.rst-content .wy-alert-danger.important .wy-alert-title,.rst-content .wy-alert-danger.note .admonition-title,.rst-content .wy-alert-danger.note .wy-alert-title,.rst-content .wy-alert-danger.seealso .admonition-title,.rst-content .wy-alert-danger.seealso .wy-alert-title,.rst-content .wy-alert-danger.tip .admonition-title,.rst-content .wy-alert-danger.tip .wy-alert-title,.rst-content .wy-alert-danger.warning .admonition-title,.rst-content .wy-alert-danger.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-danger .admonition-title,.wy-alert.wy-alert-danger .rst-content .admonition-title,.wy-alert.wy-alert-danger .wy-alert-title{background:#f29f97}.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .warning,.rst-content .wy-alert-warning.admonition,.rst-content .wy-alert-warning.danger,.rst-content .wy-alert-warning.error,.rst-content .wy-alert-warning.hint,.rst-content .wy-alert-warning.important,.rst-content .wy-alert-warning.note,.rst-content .wy-alert-warning.seealso,.rst-content .wy-alert-warning.tip,.wy-alert.wy-alert-warning{background:#ffedcc}.rst-content .admonition-todo .admonition-title,.rst-content .admonition-todo .wy-alert-title,.rst-content .attention .admonition-title,.rst-content .attention .wy-alert-title,.rst-content .caution .admonition-title,.rst-content .caution .wy-alert-title,.rst-content .warning .admonition-title,.rst-content .warning .wy-alert-title,.rst-content .wy-alert-warning.admonition .admonition-title,.rst-content .wy-alert-warning.admonition .wy-alert-title,.rst-content .wy-alert-warning.danger .admonition-title,.rst-content .wy-alert-warning.danger .wy-alert-title,.rst-content .wy-alert-warning.error .admonition-title,.rst-content .wy-alert-warning.error .wy-alert-title,.rst-content .wy-alert-warning.hint .admonition-title,.rst-content .wy-alert-warning.hint .wy-alert-title,.rst-content .wy-alert-warning.important .admonition-title,.rst-content .wy-alert-warning.important .wy-alert-title,.rst-content .wy-alert-warning.note .admonition-title,.rst-content .wy-alert-warning.note .wy-alert-title,.rst-content .wy-alert-warning.seealso .admonition-title,.rst-content .wy-alert-warning.seealso .wy-alert-title,.rst-content .wy-alert-warning.tip .admonition-title,.rst-content .wy-alert-warning.tip .wy-alert-title,.rst-content .wy-alert.wy-alert-warning .admonition-title,.wy-alert.wy-alert-warning .rst-content .admonition-title,.wy-alert.wy-alert-warning .wy-alert-title{background:#f0b37e}.rst-content .note,.rst-content .seealso,.rst-content .wy-alert-info.admonition,.rst-content .wy-alert-info.admonition-todo,.rst-content .wy-alert-info.attention,.rst-content .wy-alert-info.caution,.rst-content .wy-alert-info.danger,.rst-content .wy-alert-info.error,.rst-content .wy-alert-info.hint,.rst-content .wy-alert-info.important,.rst-content .wy-alert-info.tip,.rst-content .wy-alert-info.warning,.wy-alert.wy-alert-info{background:#e7f2fa}.rst-content .note .admonition-title,.rst-content .note .wy-alert-title,.rst-content .seealso .admonition-title,.rst-content .seealso .wy-alert-title,.rst-content .wy-alert-info.admonition-todo .admonition-title,.rst-content .wy-alert-info.admonition-todo .wy-alert-title,.rst-content .wy-alert-info.admonition .admonition-title,.rst-content .wy-alert-info.admonition .wy-alert-title,.rst-content .wy-alert-info.attention .admonition-title,.rst-content .wy-alert-info.attention .wy-alert-title,.rst-content .wy-alert-info.caution .admonition-title,.rst-content .wy-alert-info.caution .wy-alert-title,.rst-content .wy-alert-info.danger .admonition-title,.rst-content .wy-alert-info.danger .wy-alert-title,.rst-content .wy-alert-info.error .admonition-title,.rst-content .wy-alert-info.error .wy-alert-title,.rst-content .wy-alert-info.hint .admonition-title,.rst-content .wy-alert-info.hint .wy-alert-title,.rst-content .wy-alert-info.important .admonition-title,.rst-content .wy-alert-info.important .wy-alert-title,.rst-content .wy-alert-info.tip .admonition-title,.rst-content .wy-alert-info.tip .wy-alert-title,.rst-content .wy-alert-info.warning .admonition-title,.rst-content .wy-alert-info.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-info .admonition-title,.wy-alert.wy-alert-info .rst-content .admonition-title,.wy-alert.wy-alert-info .wy-alert-title{background:#6ab0de}.rst-content .hint,.rst-content .important,.rst-content .tip,.rst-content .wy-alert-success.admonition,.rst-content .wy-alert-success.admonition-todo,.rst-content .wy-alert-success.attention,.rst-content .wy-alert-success.caution,.rst-content .wy-alert-success.danger,.rst-content .wy-alert-success.error,.rst-content .wy-alert-success.note,.rst-content .wy-alert-success.seealso,.rst-content .wy-alert-success.warning,.wy-alert.wy-alert-success{background:#dbfaf4}.rst-content .hint .admonition-title,.rst-content .hint .wy-alert-title,.rst-content .important .admonition-title,.rst-content .important .wy-alert-title,.rst-content .tip .admonition-title,.rst-content .tip .wy-alert-title,.rst-content .wy-alert-success.admonition-todo .admonition-title,.rst-content .wy-alert-success.admonition-todo .wy-alert-title,.rst-content .wy-alert-success.admonition .admonition-title,.rst-content .wy-alert-success.admonition .wy-alert-title,.rst-content .wy-alert-success.attention .admonition-title,.rst-content .wy-alert-success.attention .wy-alert-title,.rst-content .wy-alert-success.caution .admonition-title,.rst-content .wy-alert-success.caution .wy-alert-title,.rst-content .wy-alert-success.danger .admonition-title,.rst-content .wy-alert-success.danger .wy-alert-title,.rst-content .wy-alert-success.error .admonition-title,.rst-content .wy-alert-success.error .wy-alert-title,.rst-content .wy-alert-success.note .admonition-title,.rst-content .wy-alert-success.note .wy-alert-title,.rst-content .wy-alert-success.seealso .admonition-title,.rst-content .wy-alert-success.seealso .wy-alert-title,.rst-content .wy-alert-success.warning .admonition-title,.rst-content .wy-alert-success.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-success .admonition-title,.wy-alert.wy-alert-success .rst-content .admonition-title,.wy-alert.wy-alert-success .wy-alert-title{background:#1abc9c}.rst-content .wy-alert-neutral.admonition,.rst-content .wy-alert-neutral.admonition-todo,.rst-content .wy-alert-neutral.attention,.rst-content .wy-alert-neutral.caution,.rst-content .wy-alert-neutral.danger,.rst-content .wy-alert-neutral.error,.rst-content .wy-alert-neutral.hint,.rst-content .wy-alert-neutral.important,.rst-content .wy-alert-neutral.note,.rst-content .wy-alert-neutral.seealso,.rst-content .wy-alert-neutral.tip,.rst-content .wy-alert-neutral.warning,.wy-alert.wy-alert-neutral{background:#f3f6f6}.rst-content .wy-alert-neutral.admonition-todo .admonition-title,.rst-content .wy-alert-neutral.admonition-todo .wy-alert-title,.rst-content .wy-alert-neutral.admonition .admonition-title,.rst-content .wy-alert-neutral.admonition .wy-alert-title,.rst-content .wy-alert-neutral.attention .admonition-title,.rst-content .wy-alert-neutral.attention .wy-alert-title,.rst-content .wy-alert-neutral.caution .admonition-title,.rst-content .wy-alert-neutral.caution .wy-alert-title,.rst-content .wy-alert-neutral.danger .admonition-title,.rst-content .wy-alert-neutral.danger .wy-alert-title,.rst-content .wy-alert-neutral.error .admonition-title,.rst-content .wy-alert-neutral.error .wy-alert-title,.rst-content .wy-alert-neutral.hint .admonition-title,.rst-content .wy-alert-neutral.hint .wy-alert-title,.rst-content .wy-alert-neutral.important .admonition-title,.rst-content .wy-alert-neutral.important .wy-alert-title,.rst-content .wy-alert-neutral.note .admonition-title,.rst-content .wy-alert-neutral.note .wy-alert-title,.rst-content .wy-alert-neutral.seealso .admonition-title,.rst-content .wy-alert-neutral.seealso .wy-alert-title,.rst-content .wy-alert-neutral.tip .admonition-title,.rst-content .wy-alert-neutral.tip .wy-alert-title,.rst-content .wy-alert-neutral.warning .admonition-title,.rst-content .wy-alert-neutral.warning .wy-alert-title,.rst-content .wy-alert.wy-alert-neutral .admonition-title,.wy-alert.wy-alert-neutral .rst-content .admonition-title,.wy-alert.wy-alert-neutral .wy-alert-title{color:#404040;background:#e1e4e5}.rst-content .wy-alert-neutral.admonition-todo a,.rst-content .wy-alert-neutral.admonition a,.rst-content .wy-alert-neutral.attention a,.rst-content .wy-alert-neutral.caution a,.rst-content .wy-alert-neutral.danger a,.rst-content .wy-alert-neutral.error a,.rst-content .wy-alert-neutral.hint a,.rst-content .wy-alert-neutral.important a,.rst-content .wy-alert-neutral.note a,.rst-content .wy-alert-neutral.seealso a,.rst-content .wy-alert-neutral.tip a,.rst-content .wy-alert-neutral.warning a,.wy-alert.wy-alert-neutral a{color:#2980b9}.rst-content .admonition-todo p:last-child,.rst-content .admonition p:last-child,.rst-content .attention p:last-child,.rst-content .caution p:last-child,.rst-content .danger p:last-child,.rst-content .error p:last-child,.rst-content .hint p:last-child,.rst-content .important p:last-child,.rst-content .note p:last-child,.rst-content .seealso p:last-child,.rst-content .tip p:last-child,.rst-content .warning p:last-child,.wy-alert p:last-child{margin-bottom:0}.wy-tray-container{position:fixed;bottom:0;left:0;z-index:600}.wy-tray-container li{display:block;width:300px;background:transparent;color:#fff;text-align:center;box-shadow:0 5px 5px 0 rgba(0,0,0,.1);padding:0 24px;min-width:20%;opacity:0;height:0;line-height:56px;overflow:hidden;-webkit-transition:all .3s ease-in;-moz-transition:all .3s ease-in;transition:all .3s ease-in}.wy-tray-container li.wy-tray-item-success{background:#27ae60}.wy-tray-container li.wy-tray-item-info{background:#2980b9}.wy-tray-container li.wy-tray-item-warning{background:#e67e22}.wy-tray-container li.wy-tray-item-danger{background:#e74c3c}.wy-tray-container li.on{opacity:1;height:56px}@media screen and (max-width:768px){.wy-tray-container{bottom:auto;top:0;width:100%}.wy-tray-container li{width:100%}}button{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle;cursor:pointer;line-height:normal;-webkit-appearance:button;*overflow:visible}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}button[disabled]{cursor:default}.btn{display:inline-block;border-radius:2px;line-height:normal;white-space:nowrap;text-align:center;cursor:pointer;font-size:100%;padding:6px 12px 8px;color:#fff;border:1px solid rgba(0,0,0,.1);background-color:#27ae60;text-decoration:none;font-weight:400;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;box-shadow:inset 0 1px 2px -1px hsla(0,0%,100%,.5),inset 0 -2px 0 0 rgba(0,0,0,.1);outline-none:false;vertical-align:middle;*display:inline;zoom:1;-webkit-user-drag:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-transition:all .1s linear;-moz-transition:all .1s linear;transition:all .1s linear}.btn-hover{background:#2e8ece;color:#fff}.btn:hover{background:#2cc36b;color:#fff}.btn:focus{background:#2cc36b;outline:0}.btn:active{box-shadow:inset 0 -1px 0 0 rgba(0,0,0,.05),inset 0 2px 0 0 rgba(0,0,0,.1);padding:8px 12px 6px}.btn:visited{color:#fff}.btn-disabled,.btn-disabled:active,.btn-disabled:focus,.btn-disabled:hover,.btn:disabled{background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);filter:alpha(opacity=40);opacity:.4;cursor:not-allowed;box-shadow:none}.btn::-moz-focus-inner{padding:0;border:0}.btn-small{font-size:80%}.btn-info{background-color:#2980b9!important}.btn-info:hover{background-color:#2e8ece!important}.btn-neutral{background-color:#f3f6f6!important;color:#404040!important}.btn-neutral:hover{background-color:#e5ebeb!important;color:#404040}.btn-neutral:visited{color:#404040!important}.btn-success{background-color:#27ae60!important}.btn-success:hover{background-color:#295!important}.btn-danger{background-color:#e74c3c!important}.btn-danger:hover{background-color:#ea6153!important}.btn-warning{background-color:#e67e22!important}.btn-warning:hover{background-color:#e98b39!important}.btn-invert{background-color:#222}.btn-invert:hover{background-color:#2f2f2f!important}.btn-link{background-color:transparent!important;color:#2980b9;box-shadow:none;border-color:transparent!important}.btn-link:active,.btn-link:hover{background-color:transparent!important;color:#409ad5!important;box-shadow:none}.btn-link:visited{color:#9b59b6}.wy-btn-group .btn,.wy-control .btn{vertical-align:middle}.wy-btn-group{margin-bottom:24px;*zoom:1}.wy-btn-group:after,.wy-btn-group:before{display:table;content:""}.wy-btn-group:after{clear:both}.wy-dropdown{position:relative;display:inline-block}.wy-dropdown-active .wy-dropdown-menu{display:block}.wy-dropdown-menu{position:absolute;left:0;display:none;float:left;top:100%;min-width:100%;background:#fcfcfc;z-index:100;border:1px solid #cfd7dd;box-shadow:0 2px 2px 0 rgba(0,0,0,.1);padding:12px}.wy-dropdown-menu>dd>a{display:block;clear:both;color:#404040;white-space:nowrap;font-size:90%;padding:0 12px;cursor:pointer}.wy-dropdown-menu>dd>a:hover{background:#2980b9;color:#fff}.wy-dropdown-menu>dd.divider{border-top:1px solid #cfd7dd;margin:6px 0}.wy-dropdown-menu>dd.search{padding-bottom:12px}.wy-dropdown-menu>dd.search input[type=search]{width:100%}.wy-dropdown-menu>dd.call-to-action{background:#e3e3e3;text-transform:uppercase;font-weight:500;font-size:80%}.wy-dropdown-menu>dd.call-to-action:hover{background:#e3e3e3}.wy-dropdown-menu>dd.call-to-action .btn{color:#fff}.wy-dropdown.wy-dropdown-up .wy-dropdown-menu{bottom:100%;top:auto;left:auto;right:0}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu{background:#fcfcfc;margin-top:2px}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu a{padding:6px 12px}.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu a:hover{background:#2980b9;color:#fff}.wy-dropdown.wy-dropdown-left .wy-dropdown-menu{right:0;left:auto;text-align:right}.wy-dropdown-arrow:before{content:" ";border-bottom:5px solid #f5f5f5;border-left:5px solid transparent;border-right:5px solid transparent;position:absolute;display:block;top:-4px;left:50%;margin-left:-3px}.wy-dropdown-arrow.wy-dropdown-arrow-left:before{left:11px}.wy-form-stacked select{display:block}.wy-form-aligned .wy-help-inline,.wy-form-aligned input,.wy-form-aligned label,.wy-form-aligned select,.wy-form-aligned textarea{display:inline-block;*display:inline;*zoom:1;vertical-align:middle}.wy-form-aligned .wy-control-group>label{display:inline-block;vertical-align:middle;width:10em;margin:6px 12px 0 0;float:left}.wy-form-aligned .wy-control{float:left}.wy-form-aligned .wy-control label{display:block}.wy-form-aligned .wy-control select{margin-top:6px}fieldset{margin:0}fieldset,legend{border:0;padding:0}legend{width:100%;white-space:normal;margin-bottom:24px;font-size:150%;*margin-left:-7px}label,legend{display:block}label{margin:0 0 .3125em;color:#333;font-size:90%}input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}.wy-control-group{margin-bottom:24px;max-width:1200px;margin-left:auto;margin-right:auto;*zoom:1}.wy-control-group:after,.wy-control-group:before{display:table;content:""}.wy-control-group:after{clear:both}.wy-control-group.wy-control-group-required>label:after{content:" *";color:#e74c3c}.wy-control-group .wy-form-full,.wy-control-group .wy-form-halves,.wy-control-group .wy-form-thirds{padding-bottom:12px}.wy-control-group .wy-form-full input[type=color],.wy-control-group .wy-form-full input[type=date],.wy-control-group .wy-form-full input[type=datetime-local],.wy-control-group .wy-form-full input[type=datetime],.wy-control-group .wy-form-full input[type=email],.wy-control-group .wy-form-full input[type=month],.wy-control-group .wy-form-full input[type=number],.wy-control-group .wy-form-full input[type=password],.wy-control-group .wy-form-full input[type=search],.wy-control-group .wy-form-full input[type=tel],.wy-control-group .wy-form-full input[type=text],.wy-control-group .wy-form-full input[type=time],.wy-control-group .wy-form-full input[type=url],.wy-control-group .wy-form-full input[type=week],.wy-control-group .wy-form-full select,.wy-control-group .wy-form-halves input[type=color],.wy-control-group .wy-form-halves input[type=date],.wy-control-group .wy-form-halves input[type=datetime-local],.wy-control-group .wy-form-halves input[type=datetime],.wy-control-group .wy-form-halves input[type=email],.wy-control-group .wy-form-halves input[type=month],.wy-control-group .wy-form-halves input[type=number],.wy-control-group .wy-form-halves input[type=password],.wy-control-group .wy-form-halves input[type=search],.wy-control-group .wy-form-halves input[type=tel],.wy-control-group .wy-form-halves input[type=text],.wy-control-group .wy-form-halves input[type=time],.wy-control-group .wy-form-halves input[type=url],.wy-control-group .wy-form-halves input[type=week],.wy-control-group .wy-form-halves select,.wy-control-group .wy-form-thirds input[type=color],.wy-control-group .wy-form-thirds input[type=date],.wy-control-group .wy-form-thirds input[type=datetime-local],.wy-control-group .wy-form-thirds input[type=datetime],.wy-control-group .wy-form-thirds input[type=email],.wy-control-group .wy-form-thirds input[type=month],.wy-control-group .wy-form-thirds input[type=number],.wy-control-group .wy-form-thirds input[type=password],.wy-control-group .wy-form-thirds input[type=search],.wy-control-group .wy-form-thirds input[type=tel],.wy-control-group .wy-form-thirds input[type=text],.wy-control-group .wy-form-thirds input[type=time],.wy-control-group .wy-form-thirds input[type=url],.wy-control-group .wy-form-thirds input[type=week],.wy-control-group .wy-form-thirds select{width:100%}.wy-control-group .wy-form-full{float:left;display:block;width:100%;margin-right:0}.wy-control-group .wy-form-full:last-child{margin-right:0}.wy-control-group .wy-form-halves{float:left;display:block;margin-right:2.35765%;width:48.82117%}.wy-control-group .wy-form-halves:last-child,.wy-control-group .wy-form-halves:nth-of-type(2n){margin-right:0}.wy-control-group .wy-form-halves:nth-of-type(odd){clear:left}.wy-control-group .wy-form-thirds{float:left;display:block;margin-right:2.35765%;width:31.76157%}.wy-control-group .wy-form-thirds:last-child,.wy-control-group .wy-form-thirds:nth-of-type(3n){margin-right:0}.wy-control-group .wy-form-thirds:nth-of-type(3n+1){clear:left}.wy-control-group.wy-control-group-no-input .wy-control,.wy-control-no-input{margin:6px 0 0;font-size:90%}.wy-control-no-input{display:inline-block}.wy-control-group.fluid-input input[type=color],.wy-control-group.fluid-input input[type=date],.wy-control-group.fluid-input input[type=datetime-local],.wy-control-group.fluid-input input[type=datetime],.wy-control-group.fluid-input input[type=email],.wy-control-group.fluid-input input[type=month],.wy-control-group.fluid-input input[type=number],.wy-control-group.fluid-input input[type=password],.wy-control-group.fluid-input input[type=search],.wy-control-group.fluid-input input[type=tel],.wy-control-group.fluid-input input[type=text],.wy-control-group.fluid-input input[type=time],.wy-control-group.fluid-input input[type=url],.wy-control-group.fluid-input input[type=week]{width:100%}.wy-form-message-inline{padding-left:.3em;color:#666;font-size:90%}.wy-form-message{display:block;color:#999;font-size:70%;margin-top:.3125em;font-style:italic}.wy-form-message p{font-size:inherit;font-style:italic;margin-bottom:6px}.wy-form-message p:last-child{margin-bottom:0}input{line-height:normal}input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;*overflow:visible}input[type=color],input[type=date],input[type=datetime-local],input[type=datetime],input[type=email],input[type=month],input[type=number],input[type=password],input[type=search],input[type=tel],input[type=text],input[type=time],input[type=url],input[type=week]{-webkit-appearance:none;padding:6px;display:inline-block;border:1px solid #ccc;font-size:80%;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;box-shadow:inset 0 1px 3px #ddd;border-radius:0;-webkit-transition:border .3s linear;-moz-transition:border .3s linear;transition:border .3s linear}input[type=datetime-local]{padding:.34375em .625em}input[disabled]{cursor:default}input[type=checkbox],input[type=radio]{padding:0;margin-right:.3125em;*height:13px;*width:13px}input[type=checkbox],input[type=radio],input[type=search]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}input[type=color]:focus,input[type=date]:focus,input[type=datetime-local]:focus,input[type=datetime]:focus,input[type=email]:focus,input[type=month]:focus,input[type=number]:focus,input[type=password]:focus,input[type=search]:focus,input[type=tel]:focus,input[type=text]:focus,input[type=time]:focus,input[type=url]:focus,input[type=week]:focus{outline:0;outline:thin dotted\9;border-color:#333}input.no-focus:focus{border-color:#ccc!important}input[type=checkbox]:focus,input[type=file]:focus,input[type=radio]:focus{outline:thin dotted #333;outline:1px auto #129fea}input[type=color][disabled],input[type=date][disabled],input[type=datetime-local][disabled],input[type=datetime][disabled],input[type=email][disabled],input[type=month][disabled],input[type=number][disabled],input[type=password][disabled],input[type=search][disabled],input[type=tel][disabled],input[type=text][disabled],input[type=time][disabled],input[type=url][disabled],input[type=week][disabled]{cursor:not-allowed;background-color:#fafafa}input:focus:invalid,select:focus:invalid,textarea:focus:invalid{color:#e74c3c;border:1px solid #e74c3c}input:focus:invalid:focus,select:focus:invalid:focus,textarea:focus:invalid:focus{border-color:#e74c3c}input[type=checkbox]:focus:invalid:focus,input[type=file]:focus:invalid:focus,input[type=radio]:focus:invalid:focus{outline-color:#e74c3c}input.wy-input-large{padding:12px;font-size:100%}textarea{overflow:auto;vertical-align:top;width:100%;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif}select,textarea{padding:.5em .625em;display:inline-block;border:1px solid #ccc;font-size:80%;box-shadow:inset 0 1px 3px #ddd;-webkit-transition:border .3s linear;-moz-transition:border .3s linear;transition:border .3s linear}select{border:1px solid #ccc;background-color:#fff}select[multiple]{height:auto}select:focus,textarea:focus{outline:0}input[readonly],select[disabled],select[readonly],textarea[disabled],textarea[readonly]{cursor:not-allowed;background-color:#fafafa}input[type=checkbox][disabled],input[type=radio][disabled]{cursor:not-allowed}.wy-checkbox,.wy-radio{margin:6px 0;color:#404040;display:block}.wy-checkbox input,.wy-radio input{vertical-align:baseline}.wy-form-message-inline{display:inline-block;*display:inline;*zoom:1;vertical-align:middle}.wy-input-prefix,.wy-input-suffix{white-space:nowrap;padding:6px}.wy-input-prefix .wy-input-context,.wy-input-suffix .wy-input-context{line-height:27px;padding:0 8px;display:inline-block;font-size:80%;background-color:#f3f6f6;border:1px solid #ccc;color:#999}.wy-input-suffix .wy-input-context{border-left:0}.wy-input-prefix .wy-input-context{border-right:0}.wy-switch{position:relative;display:block;height:24px;margin-top:12px;cursor:pointer}.wy-switch:before{left:0;top:0;width:36px;height:12px;background:#ccc}.wy-switch:after,.wy-switch:before{position:absolute;content:"";display:block;border-radius:4px;-webkit-transition:all .2s ease-in-out;-moz-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.wy-switch:after{width:18px;height:18px;background:#999;left:-3px;top:-3px}.wy-switch span{position:absolute;left:48px;display:block;font-size:12px;color:#ccc;line-height:1}.wy-switch.active:before{background:#1e8449}.wy-switch.active:after{left:24px;background:#27ae60}.wy-switch.disabled{cursor:not-allowed;opacity:.8}.wy-control-group.wy-control-group-error .wy-form-message,.wy-control-group.wy-control-group-error>label{color:#e74c3c}.wy-control-group.wy-control-group-error input[type=color],.wy-control-group.wy-control-group-error input[type=date],.wy-control-group.wy-control-group-error input[type=datetime-local],.wy-control-group.wy-control-group-error input[type=datetime],.wy-control-group.wy-control-group-error input[type=email],.wy-control-group.wy-control-group-error input[type=month],.wy-control-group.wy-control-group-error input[type=number],.wy-control-group.wy-control-group-error input[type=password],.wy-control-group.wy-control-group-error input[type=search],.wy-control-group.wy-control-group-error input[type=tel],.wy-control-group.wy-control-group-error input[type=text],.wy-control-group.wy-control-group-error input[type=time],.wy-control-group.wy-control-group-error input[type=url],.wy-control-group.wy-control-group-error input[type=week],.wy-control-group.wy-control-group-error textarea{border:1px solid #e74c3c}.wy-inline-validate{white-space:nowrap}.wy-inline-validate .wy-input-context{padding:.5em .625em;display:inline-block;font-size:80%}.wy-inline-validate.wy-inline-validate-success .wy-input-context{color:#27ae60}.wy-inline-validate.wy-inline-validate-danger .wy-input-context{color:#e74c3c}.wy-inline-validate.wy-inline-validate-warning .wy-input-context{color:#e67e22}.wy-inline-validate.wy-inline-validate-info .wy-input-context{color:#2980b9}.rotate-90{-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-ms-transform:rotate(90deg);-o-transform:rotate(90deg);transform:rotate(90deg)}.rotate-180{-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-ms-transform:rotate(180deg);-o-transform:rotate(180deg);transform:rotate(180deg)}.rotate-270{-webkit-transform:rotate(270deg);-moz-transform:rotate(270deg);-ms-transform:rotate(270deg);-o-transform:rotate(270deg);transform:rotate(270deg)}.mirror{-webkit-transform:scaleX(-1);-moz-transform:scaleX(-1);-ms-transform:scaleX(-1);-o-transform:scaleX(-1);transform:scaleX(-1)}.mirror.rotate-90{-webkit-transform:scaleX(-1) rotate(90deg);-moz-transform:scaleX(-1) rotate(90deg);-ms-transform:scaleX(-1) rotate(90deg);-o-transform:scaleX(-1) rotate(90deg);transform:scaleX(-1) rotate(90deg)}.mirror.rotate-180{-webkit-transform:scaleX(-1) rotate(180deg);-moz-transform:scaleX(-1) rotate(180deg);-ms-transform:scaleX(-1) rotate(180deg);-o-transform:scaleX(-1) rotate(180deg);transform:scaleX(-1) rotate(180deg)}.mirror.rotate-270{-webkit-transform:scaleX(-1) rotate(270deg);-moz-transform:scaleX(-1) rotate(270deg);-ms-transform:scaleX(-1) rotate(270deg);-o-transform:scaleX(-1) rotate(270deg);transform:scaleX(-1) rotate(270deg)}@media only screen and (max-width:480px){.wy-form button[type=submit]{margin:.7em 0 0}.wy-form input[type=color],.wy-form input[type=date],.wy-form input[type=datetime-local],.wy-form input[type=datetime],.wy-form input[type=email],.wy-form input[type=month],.wy-form input[type=number],.wy-form input[type=password],.wy-form input[type=search],.wy-form input[type=tel],.wy-form input[type=text],.wy-form input[type=time],.wy-form input[type=url],.wy-form input[type=week],.wy-form label{margin-bottom:.3em;display:block}.wy-form input[type=color],.wy-form input[type=date],.wy-form input[type=datetime-local],.wy-form input[type=datetime],.wy-form input[type=email],.wy-form input[type=month],.wy-form input[type=number],.wy-form input[type=password],.wy-form input[type=search],.wy-form input[type=tel],.wy-form input[type=time],.wy-form input[type=url],.wy-form input[type=week]{margin-bottom:0}.wy-form-aligned .wy-control-group label{margin-bottom:.3em;text-align:left;display:block;width:100%}.wy-form-aligned .wy-control{margin:1.5em 0 0}.wy-form-message,.wy-form-message-inline,.wy-form .wy-help-inline{display:block;font-size:80%;padding:6px 0}}@media screen and (max-width:768px){.tablet-hide{display:none}}@media screen and (max-width:480px){.mobile-hide{display:none}}.float-left{float:left}.float-right{float:right}.full-width{width:100%}.rst-content table.docutils,.rst-content table.field-list,.wy-table{border-collapse:collapse;border-spacing:0;empty-cells:show;margin-bottom:24px}.rst-content table.docutils caption,.rst-content table.field-list caption,.wy-table caption{color:#000;font:italic 85%/1 arial,sans-serif;padding:1em 0;text-align:center}.rst-content table.docutils td,.rst-content table.docutils th,.rst-content table.field-list td,.rst-content table.field-list th,.wy-table td,.wy-table th{font-size:90%;margin:0;overflow:visible;padding:8px 16px}.rst-content table.docutils td:first-child,.rst-content table.docutils th:first-child,.rst-content table.field-list td:first-child,.rst-content table.field-list th:first-child,.wy-table td:first-child,.wy-table th:first-child{border-left-width:0}.rst-content table.docutils thead,.rst-content table.field-list thead,.wy-table thead{color:#000;text-align:left;vertical-align:bottom;white-space:nowrap}.rst-content table.docutils thead th,.rst-content table.field-list thead th,.wy-table thead th{font-weight:700;border-bottom:2px solid #e1e4e5}.rst-content table.docutils td,.rst-content table.field-list td,.wy-table td{background-color:transparent;vertical-align:middle}.rst-content table.docutils td p,.rst-content table.field-list td p,.wy-table td p{line-height:18px}.rst-content table.docutils td p:last-child,.rst-content table.field-list td p:last-child,.wy-table td p:last-child{margin-bottom:0}.rst-content table.docutils .wy-table-cell-min,.rst-content table.field-list .wy-table-cell-min,.wy-table .wy-table-cell-min{width:1%;padding-right:0}.rst-content table.docutils .wy-table-cell-min input[type=checkbox],.rst-content table.field-list .wy-table-cell-min input[type=checkbox],.wy-table .wy-table-cell-min input[type=checkbox]{margin:0}.wy-table-secondary{color:grey;font-size:90%}.wy-table-tertiary{color:grey;font-size:80%}.rst-content table.docutils:not(.field-list) tr:nth-child(2n-1) td,.wy-table-backed,.wy-table-odd td,.wy-table-striped tr:nth-child(2n-1) td{background-color:#f3f6f6}.rst-content table.docutils,.wy-table-bordered-all{border:1px solid #e1e4e5}.rst-content table.docutils td,.wy-table-bordered-all td{border-bottom:1px solid #e1e4e5;border-left:1px solid #e1e4e5}.rst-content table.docutils tbody>tr:last-child td,.wy-table-bordered-all tbody>tr:last-child td{border-bottom-width:0}.wy-table-bordered{border:1px solid #e1e4e5}.wy-table-bordered-rows td{border-bottom:1px solid #e1e4e5}.wy-table-bordered-rows tbody>tr:last-child td{border-bottom-width:0}.wy-table-horizontal td,.wy-table-horizontal th{border-width:0 0 1px;border-bottom:1px solid #e1e4e5}.wy-table-horizontal tbody>tr:last-child td{border-bottom-width:0}.wy-table-responsive{margin-bottom:24px;max-width:100%;overflow:auto}.wy-table-responsive table{margin-bottom:0!important}.wy-table-responsive table td,.wy-table-responsive table th{white-space:nowrap}a{color:#2980b9;text-decoration:none;cursor:pointer}a:hover{color:#3091d1}a:visited{color:#9b59b6}html{height:100%}body,html{overflow-x:hidden}body{font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;font-weight:400;color:#404040;min-height:100%;background:#edf0f2}.wy-text-left{text-align:left}.wy-text-center{text-align:center}.wy-text-right{text-align:right}.wy-text-large{font-size:120%}.wy-text-normal{font-size:100%}.wy-text-small,small{font-size:80%}.wy-text-strike{text-decoration:line-through}.wy-text-warning{color:#e67e22!important}a.wy-text-warning:hover{color:#eb9950!important}.wy-text-info{color:#2980b9!important}a.wy-text-info:hover{color:#409ad5!important}.wy-text-success{color:#27ae60!important}a.wy-text-success:hover{color:#36d278!important}.wy-text-danger{color:#e74c3c!important}a.wy-text-danger:hover{color:#ed7669!important}.wy-text-neutral{color:#404040!important}a.wy-text-neutral:hover{color:#595959!important}.rst-content .toctree-wrapper>p.caption,h1,h2,h3,h4,h5,h6,legend{margin-top:0;font-weight:700;font-family:Roboto Slab,ff-tisa-web-pro,Georgia,Arial,sans-serif}p{line-height:24px;font-size:16px;margin:0 0 24px}h1{font-size:175%}.rst-content .toctree-wrapper>p.caption,h2{font-size:150%}h3{font-size:125%}h4{font-size:115%}h5{font-size:110%}h6{font-size:100%}hr{display:block;height:1px;border:0;border-top:1px solid #e1e4e5;margin:24px 0;padding:0}.rst-content code,.rst-content tt,code{white-space:nowrap;max-width:100%;background:#fff;border:1px solid #e1e4e5;font-size:75%;padding:0 5px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;color:#e74c3c;overflow-x:auto}.rst-content tt.code-large,code.code-large{font-size:90%}.rst-content .section ul,.rst-content .toctree-wrapper ul,.rst-content section ul,.wy-plain-list-disc,article ul{list-style:disc;line-height:24px;margin-bottom:24px}.rst-content .section ul li,.rst-content .toctree-wrapper ul li,.rst-content section ul li,.wy-plain-list-disc li,article ul li{list-style:disc;margin-left:24px}.rst-content .section ul li p:last-child,.rst-content .section ul li ul,.rst-content .toctree-wrapper ul li p:last-child,.rst-content .toctree-wrapper ul li ul,.rst-content section ul li p:last-child,.rst-content section ul li ul,.wy-plain-list-disc li p:last-child,.wy-plain-list-disc li ul,article ul li p:last-child,article ul li ul{margin-bottom:0}.rst-content .section ul li li,.rst-content .toctree-wrapper ul li li,.rst-content section ul li li,.wy-plain-list-disc li li,article ul li li{list-style:circle}.rst-content .section ul li li li,.rst-content .toctree-wrapper ul li li li,.rst-content section ul li li li,.wy-plain-list-disc li li li,article ul li li li{list-style:square}.rst-content .section ul li ol li,.rst-content .toctree-wrapper ul li ol li,.rst-content section ul li ol li,.wy-plain-list-disc li ol li,article ul li ol li{list-style:decimal}.rst-content .section ol,.rst-content .section ol.arabic,.rst-content .toctree-wrapper ol,.rst-content .toctree-wrapper ol.arabic,.rst-content section ol,.rst-content section ol.arabic,.wy-plain-list-decimal,article ol{list-style:decimal;line-height:24px;margin-bottom:24px}.rst-content .section ol.arabic li,.rst-content .section ol li,.rst-content .toctree-wrapper ol.arabic li,.rst-content .toctree-wrapper ol li,.rst-content section ol.arabic li,.rst-content section ol li,.wy-plain-list-decimal li,article ol li{list-style:decimal;margin-left:24px}.rst-content .section ol.arabic li ul,.rst-content .section ol li p:last-child,.rst-content .section ol li ul,.rst-content .toctree-wrapper ol.arabic li ul,.rst-content .toctree-wrapper ol li p:last-child,.rst-content .toctree-wrapper ol li ul,.rst-content section ol.arabic li ul,.rst-content section ol li p:last-child,.rst-content section ol li ul,.wy-plain-list-decimal li p:last-child,.wy-plain-list-decimal li ul,article ol li p:last-child,article ol li ul{margin-bottom:0}.rst-content .section ol.arabic li ul li,.rst-content .section ol li ul li,.rst-content .toctree-wrapper ol.arabic li ul li,.rst-content .toctree-wrapper ol li ul li,.rst-content section ol.arabic li ul li,.rst-content section ol li ul li,.wy-plain-list-decimal li ul li,article ol li ul li{list-style:disc}.wy-breadcrumbs{*zoom:1}.wy-breadcrumbs:after,.wy-breadcrumbs:before{display:table;content:""}.wy-breadcrumbs:after{clear:both}.wy-breadcrumbs>li{display:inline-block;padding-top:5px}.wy-breadcrumbs>li.wy-breadcrumbs-aside{float:right}.rst-content .wy-breadcrumbs>li code,.rst-content .wy-breadcrumbs>li tt,.wy-breadcrumbs>li .rst-content tt,.wy-breadcrumbs>li code{all:inherit;color:inherit}.breadcrumb-item:before{content:"/";color:#bbb;font-size:13px;padding:0 6px 0 3px}.wy-breadcrumbs-extra{margin-bottom:0;color:#b3b3b3;font-size:80%;display:inline-block}@media screen and (max-width:480px){.wy-breadcrumbs-extra,.wy-breadcrumbs li.wy-breadcrumbs-aside{display:none}}@media print{.wy-breadcrumbs li.wy-breadcrumbs-aside{display:none}}html{font-size:16px}.wy-affix{position:fixed;top:1.618em}.wy-menu a:hover{text-decoration:none}.wy-menu-horiz{*zoom:1}.wy-menu-horiz:after,.wy-menu-horiz:before{display:table;content:""}.wy-menu-horiz:after{clear:both}.wy-menu-horiz li,.wy-menu-horiz ul{display:inline-block}.wy-menu-horiz li:hover{background:hsla(0,0%,100%,.1)}.wy-menu-horiz li.divide-left{border-left:1px solid #404040}.wy-menu-horiz li.divide-right{border-right:1px solid #404040}.wy-menu-horiz a{height:32px;display:inline-block;line-height:32px;padding:0 16px}.wy-menu-vertical{width:300px}.wy-menu-vertical header,.wy-menu-vertical p.caption{color:#55a5d9;height:32px;line-height:32px;padding:0 1.618em;margin:12px 0 0;display:block;font-weight:700;text-transform:uppercase;font-size:85%;white-space:nowrap}.wy-menu-vertical ul{margin-bottom:0}.wy-menu-vertical li.divide-top{border-top:1px solid #404040}.wy-menu-vertical li.divide-bottom{border-bottom:1px solid #404040}.wy-menu-vertical li.current{background:#e3e3e3}.wy-menu-vertical li.current a{color:grey;border-right:1px solid #c9c9c9;padding:.4045em 2.427em}.wy-menu-vertical li.current a:hover{background:#d6d6d6}.rst-content .wy-menu-vertical li tt,.wy-menu-vertical li .rst-content tt,.wy-menu-vertical li code{border:none;background:inherit;color:inherit;padding-left:0;padding-right:0}.wy-menu-vertical li button.toctree-expand{display:block;float:left;margin-left:-1.2em;line-height:18px;color:#4d4d4d;border:none;background:none;padding:0}.wy-menu-vertical li.current>a,.wy-menu-vertical li.on a{color:#404040;font-weight:700;position:relative;background:#fcfcfc;border:none;padding:.4045em 1.618em}.wy-menu-vertical li.current>a:hover,.wy-menu-vertical li.on a:hover{background:#fcfcfc}.wy-menu-vertical li.current>a:hover button.toctree-expand,.wy-menu-vertical li.on a:hover button.toctree-expand{color:grey}.wy-menu-vertical li.current>a button.toctree-expand,.wy-menu-vertical li.on a button.toctree-expand{display:block;line-height:18px;color:#333}.wy-menu-vertical li.toctree-l1.current>a{border-bottom:1px solid #c9c9c9;border-top:1px solid #c9c9c9}.wy-menu-vertical .toctree-l1.current .toctree-l2>ul,.wy-menu-vertical .toctree-l2.current .toctree-l3>ul,.wy-menu-vertical .toctree-l3.current .toctree-l4>ul,.wy-menu-vertical .toctree-l4.current .toctree-l5>ul,.wy-menu-vertical .toctree-l5.current .toctree-l6>ul,.wy-menu-vertical .toctree-l6.current .toctree-l7>ul,.wy-menu-vertical .toctree-l7.current .toctree-l8>ul,.wy-menu-vertical .toctree-l8.current .toctree-l9>ul,.wy-menu-vertical .toctree-l9.current .toctree-l10>ul,.wy-menu-vertical .toctree-l10.current .toctree-l11>ul{display:none}.wy-menu-vertical .toctree-l1.current .current.toctree-l2>ul,.wy-menu-vertical .toctree-l2.current .current.toctree-l3>ul,.wy-menu-vertical .toctree-l3.current .current.toctree-l4>ul,.wy-menu-vertical .toctree-l4.current .current.toctree-l5>ul,.wy-menu-vertical .toctree-l5.current .current.toctree-l6>ul,.wy-menu-vertical .toctree-l6.current .current.toctree-l7>ul,.wy-menu-vertical .toctree-l7.current .current.toctree-l8>ul,.wy-menu-vertical .toctree-l8.current .current.toctree-l9>ul,.wy-menu-vertical .toctree-l9.current .current.toctree-l10>ul,.wy-menu-vertical .toctree-l10.current .current.toctree-l11>ul{display:block}.wy-menu-vertical li.toctree-l3,.wy-menu-vertical li.toctree-l4{font-size:.9em}.wy-menu-vertical li.toctree-l2 a,.wy-menu-vertical li.toctree-l3 a,.wy-menu-vertical li.toctree-l4 a,.wy-menu-vertical li.toctree-l5 a,.wy-menu-vertical li.toctree-l6 a,.wy-menu-vertical li.toctree-l7 a,.wy-menu-vertical li.toctree-l8 a,.wy-menu-vertical li.toctree-l9 a,.wy-menu-vertical li.toctree-l10 a{color:#404040}.wy-menu-vertical li.toctree-l2 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l3 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l4 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l5 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l6 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l7 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l8 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l9 a:hover button.toctree-expand,.wy-menu-vertical li.toctree-l10 a:hover button.toctree-expand{color:grey}.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a,.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a,.wy-menu-vertical li.toctree-l4.current li.toctree-l5>a,.wy-menu-vertical li.toctree-l5.current li.toctree-l6>a,.wy-menu-vertical li.toctree-l6.current li.toctree-l7>a,.wy-menu-vertical li.toctree-l7.current li.toctree-l8>a,.wy-menu-vertical li.toctree-l8.current li.toctree-l9>a,.wy-menu-vertical li.toctree-l9.current li.toctree-l10>a,.wy-menu-vertical li.toctree-l10.current li.toctree-l11>a{display:block}.wy-menu-vertical li.toctree-l2.current>a{padding:.4045em 2.427em}.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a{padding:.4045em 1.618em .4045em 4.045em}.wy-menu-vertical li.toctree-l3.current>a{padding:.4045em 4.045em}.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a{padding:.4045em 1.618em .4045em 5.663em}.wy-menu-vertical li.toctree-l4.current>a{padding:.4045em 5.663em}.wy-menu-vertical li.toctree-l4.current li.toctree-l5>a{padding:.4045em 1.618em .4045em 7.281em}.wy-menu-vertical li.toctree-l5.current>a{padding:.4045em 7.281em}.wy-menu-vertical li.toctree-l5.current li.toctree-l6>a{padding:.4045em 1.618em .4045em 8.899em}.wy-menu-vertical li.toctree-l6.current>a{padding:.4045em 8.899em}.wy-menu-vertical li.toctree-l6.current li.toctree-l7>a{padding:.4045em 1.618em .4045em 10.517em}.wy-menu-vertical li.toctree-l7.current>a{padding:.4045em 10.517em}.wy-menu-vertical li.toctree-l7.current li.toctree-l8>a{padding:.4045em 1.618em .4045em 12.135em}.wy-menu-vertical li.toctree-l8.current>a{padding:.4045em 12.135em}.wy-menu-vertical li.toctree-l8.current li.toctree-l9>a{padding:.4045em 1.618em .4045em 13.753em}.wy-menu-vertical li.toctree-l9.current>a{padding:.4045em 13.753em}.wy-menu-vertical li.toctree-l9.current li.toctree-l10>a{padding:.4045em 1.618em .4045em 15.371em}.wy-menu-vertical li.toctree-l10.current>a{padding:.4045em 15.371em}.wy-menu-vertical li.toctree-l10.current li.toctree-l11>a{padding:.4045em 1.618em .4045em 16.989em}.wy-menu-vertical li.toctree-l2.current>a,.wy-menu-vertical li.toctree-l2.current li.toctree-l3>a{background:#c9c9c9}.wy-menu-vertical li.toctree-l2 button.toctree-expand{color:#a3a3a3}.wy-menu-vertical li.toctree-l3.current>a,.wy-menu-vertical li.toctree-l3.current li.toctree-l4>a{background:#bdbdbd}.wy-menu-vertical li.toctree-l3 button.toctree-expand{color:#969696}.wy-menu-vertical li.current ul{display:block}.wy-menu-vertical li ul{margin-bottom:0;display:none}.wy-menu-vertical li ul li a{margin-bottom:0;color:#d9d9d9;font-weight:400}.wy-menu-vertical a{line-height:18px;padding:.4045em 1.618em;display:block;position:relative;font-size:90%;color:#d9d9d9}.wy-menu-vertical a:hover{background-color:#4e4a4a;cursor:pointer}.wy-menu-vertical a:hover button.toctree-expand{color:#d9d9d9}.wy-menu-vertical a:active{background-color:#2980b9;cursor:pointer;color:#fff}.wy-menu-vertical a:active button.toctree-expand{color:#fff}.wy-side-nav-search{display:block;width:300px;padding:.809em;margin-bottom:.809em;z-index:200;background-color:#2980b9;text-align:center;color:#fcfcfc}.wy-side-nav-search input[type=text]{width:100%;border-radius:50px;padding:6px 12px;border-color:#2472a4}.wy-side-nav-search img{display:block;margin:auto auto .809em;height:45px;width:45px;background-color:#2980b9;padding:5px;border-radius:100%}.wy-side-nav-search .wy-dropdown>a,.wy-side-nav-search>a{color:#fcfcfc;font-size:100%;font-weight:700;display:inline-block;padding:4px 6px;margin-bottom:.809em;max-width:100%}.wy-side-nav-search .wy-dropdown>a:hover,.wy-side-nav-search>a:hover{background:hsla(0,0%,100%,.1)}.wy-side-nav-search .wy-dropdown>a img.logo,.wy-side-nav-search>a img.logo{display:block;margin:0 auto;height:auto;width:auto;border-radius:0;max-width:100%;background:transparent}.wy-side-nav-search .wy-dropdown>a.icon img.logo,.wy-side-nav-search>a.icon img.logo{margin-top:.85em}.wy-side-nav-search>div.version{margin-top:-.4045em;margin-bottom:.809em;font-weight:400;color:hsla(0,0%,100%,.3)}.wy-nav .wy-menu-vertical header{color:#2980b9}.wy-nav .wy-menu-vertical a{color:#b3b3b3}.wy-nav .wy-menu-vertical a:hover{background-color:#2980b9;color:#fff}[data-menu-wrap]{-webkit-transition:all .2s ease-in;-moz-transition:all .2s ease-in;transition:all .2s ease-in;position:absolute;opacity:1;width:100%;opacity:0}[data-menu-wrap].move-center{left:0;right:auto;opacity:1}[data-menu-wrap].move-left{right:auto;left:-100%;opacity:0}[data-menu-wrap].move-right{right:-100%;left:auto;opacity:0}.wy-body-for-nav{background:#fcfcfc}.wy-grid-for-nav{position:absolute;width:100%;height:100%}.wy-nav-side{position:fixed;top:0;bottom:0;left:0;padding-bottom:2em;width:300px;overflow-x:hidden;overflow-y:hidden;min-height:100%;color:#9b9b9b;background:#343131;z-index:200}.wy-side-scroll{width:320px;position:relative;overflow-x:hidden;overflow-y:scroll;height:100%}.wy-nav-top{display:none;background:#2980b9;color:#fff;padding:.4045em .809em;position:relative;line-height:50px;text-align:center;font-size:100%;*zoom:1}.wy-nav-top:after,.wy-nav-top:before{display:table;content:""}.wy-nav-top:after{clear:both}.wy-nav-top a{color:#fff;font-weight:700}.wy-nav-top img{margin-right:12px;height:45px;width:45px;background-color:#2980b9;padding:5px;border-radius:100%}.wy-nav-top i{font-size:30px;float:left;cursor:pointer;padding-top:inherit}.wy-nav-content-wrap{margin-left:300px;background:#fcfcfc;min-height:100%}.wy-nav-content{padding:1.618em 3.236em;height:100%;max-width:800px;margin:auto}.wy-body-mask{position:fixed;width:100%;height:100%;background:rgba(0,0,0,.2);display:none;z-index:499}.wy-body-mask.on{display:block}footer{color:grey}footer p{margin-bottom:12px}.rst-content footer span.commit tt,footer span.commit .rst-content tt,footer span.commit code{padding:0;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;font-size:1em;background:none;border:none;color:grey}.rst-footer-buttons{*zoom:1}.rst-footer-buttons:after,.rst-footer-buttons:before{width:100%;display:table;content:""}.rst-footer-buttons:after{clear:both}.rst-breadcrumbs-buttons{margin-top:12px;*zoom:1}.rst-breadcrumbs-buttons:after,.rst-breadcrumbs-buttons:before{display:table;content:""}.rst-breadcrumbs-buttons:after{clear:both}#search-results .search li{margin-bottom:24px;border-bottom:1px solid #e1e4e5;padding-bottom:24px}#search-results .search li:first-child{border-top:1px solid #e1e4e5;padding-top:24px}#search-results .search li a{font-size:120%;margin-bottom:12px;display:inline-block}#search-results .context{color:grey;font-size:90%}.genindextable li>ul{margin-left:24px}@media screen and (max-width:768px){.wy-body-for-nav{background:#fcfcfc}.wy-nav-top{display:block}.wy-nav-side{left:-300px}.wy-nav-side.shift{width:85%;left:0}.wy-menu.wy-menu-vertical,.wy-side-nav-search,.wy-side-scroll{width:auto}.wy-nav-content-wrap{margin-left:0}.wy-nav-content-wrap .wy-nav-content{padding:1.618em}.wy-nav-content-wrap.shift{position:fixed;min-width:100%;left:85%;top:0;height:100%;overflow:hidden}}@media screen and (min-width:1100px){.wy-nav-content-wrap{background:rgba(0,0,0,.05)}.wy-nav-content{margin:0;background:#fcfcfc}}@media print{.rst-versions,.wy-nav-side,footer{display:none}.wy-nav-content-wrap{margin-left:0}}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;z-index:400}.rst-versions a{color:#2980b9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27ae60;*zoom:1}.rst-versions .rst-current-version:after,.rst-versions .rst-current-version:before{display:table;content:""}.rst-versions .rst-current-version:after{clear:both}.rst-content .code-block-caption .rst-versions .rst-current-version .headerlink,.rst-content .eqno .rst-versions .rst-current-version .headerlink,.rst-content .rst-versions .rst-current-version .admonition-title,.rst-content code.download .rst-versions .rst-current-version span:first-child,.rst-content dl dt .rst-versions .rst-current-version .headerlink,.rst-content h1 .rst-versions .rst-current-version .headerlink,.rst-content h2 .rst-versions .rst-current-version .headerlink,.rst-content h3 .rst-versions .rst-current-version .headerlink,.rst-content h4 .rst-versions .rst-current-version .headerlink,.rst-content h5 .rst-versions .rst-current-version .headerlink,.rst-content h6 .rst-versions .rst-current-version .headerlink,.rst-content p .rst-versions .rst-current-version .headerlink,.rst-content table>caption .rst-versions .rst-current-version .headerlink,.rst-content tt.download .rst-versions .rst-current-version span:first-child,.rst-versions .rst-current-version .fa,.rst-versions .rst-current-version .icon,.rst-versions .rst-current-version .rst-content .admonition-title,.rst-versions .rst-current-version .rst-content .code-block-caption .headerlink,.rst-versions .rst-current-version .rst-content .eqno .headerlink,.rst-versions .rst-current-version .rst-content code.download span:first-child,.rst-versions .rst-current-version .rst-content dl dt .headerlink,.rst-versions .rst-current-version .rst-content h1 .headerlink,.rst-versions .rst-current-version .rst-content h2 .headerlink,.rst-versions .rst-current-version .rst-content h3 .headerlink,.rst-versions .rst-current-version .rst-content h4 .headerlink,.rst-versions .rst-current-version .rst-content h5 .headerlink,.rst-versions .rst-current-version .rst-content h6 .headerlink,.rst-versions .rst-current-version .rst-content p .headerlink,.rst-versions .rst-current-version .rst-content table>caption .headerlink,.rst-versions .rst-current-version .rst-content tt.download span:first-child,.rst-versions .rst-current-version .wy-menu-vertical li button.toctree-expand,.wy-menu-vertical li .rst-versions .rst-current-version button.toctree-expand{color:#fcfcfc}.rst-versions .rst-current-version .fa-book,.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#e74c3c;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#f1c40f;color:#000}.rst-versions.shift-up{height:auto;max-height:100%;overflow-y:scroll}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:grey;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:1px solid #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px;max-height:90%}.rst-versions.rst-badge .fa-book,.rst-versions.rst-badge .icon-book{float:none;line-height:30px}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book,.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge>.rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width:768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}}.rst-content .toctree-wrapper>p.caption,.rst-content h1,.rst-content h2,.rst-content h3,.rst-content h4,.rst-content h5,.rst-content h6{margin-bottom:24px}.rst-content img{max-width:100%;height:auto}.rst-content div.figure,.rst-content figure{margin-bottom:24px}.rst-content div.figure .caption-text,.rst-content figure .caption-text{font-style:italic}.rst-content div.figure p:last-child.caption,.rst-content figure p:last-child.caption{margin-bottom:0}.rst-content div.figure.align-center,.rst-content figure.align-center{text-align:center}.rst-content .section>a>img,.rst-content .section>img,.rst-content section>a>img,.rst-content section>img{margin-bottom:24px}.rst-content abbr[title]{text-decoration:none}.rst-content.style-external-links a.reference.external:after{font-family:FontAwesome;content:"\f08e";color:#b3b3b3;vertical-align:super;font-size:60%;margin:0 .2em}.rst-content blockquote{margin-left:24px;line-height:24px;margin-bottom:24px}.rst-content pre.literal-block{white-space:pre;margin:0;padding:12px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;display:block;overflow:auto}.rst-content div[class^=highlight],.rst-content pre.literal-block{border:1px solid #e1e4e5;overflow-x:auto;margin:1px 0 24px}.rst-content div[class^=highlight] div[class^=highlight],.rst-content pre.literal-block div[class^=highlight]{padding:0;border:none;margin:0}.rst-content div[class^=highlight] td.code{width:100%}.rst-content .linenodiv pre{border-right:1px solid #e6e9ea;margin:0;padding:12px;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;user-select:none;pointer-events:none}.rst-content div[class^=highlight] pre{white-space:pre;margin:0;padding:12px;display:block;overflow:auto}.rst-content div[class^=highlight] pre .hll{display:block;margin:0 -12px;padding:0 12px}.rst-content .linenodiv pre,.rst-content div[class^=highlight] pre,.rst-content pre.literal-block{font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;font-size:12px;line-height:1.4}.rst-content div.highlight .gp,.rst-content div.highlight span.linenos{user-select:none;pointer-events:none}.rst-content div.highlight span.linenos{display:inline-block;padding-left:0;padding-right:12px;margin-right:12px;border-right:1px solid #e6e9ea}.rst-content .code-block-caption{font-style:italic;font-size:85%;line-height:1;padding:1em 0;text-align:center}@media print{.rst-content .codeblock,.rst-content div[class^=highlight],.rst-content div[class^=highlight] pre{white-space:pre-wrap}}.rst-content .admonition,.rst-content .admonition-todo,.rst-content .attention,.rst-content .caution,.rst-content .danger,.rst-content .error,.rst-content .hint,.rst-content .important,.rst-content .note,.rst-content .seealso,.rst-content .tip,.rst-content .warning{clear:both}.rst-content .admonition-todo .last,.rst-content .admonition-todo>:last-child,.rst-content .admonition .last,.rst-content .admonition>:last-child,.rst-content .attention .last,.rst-content .attention>:last-child,.rst-content .caution .last,.rst-content .caution>:last-child,.rst-content .danger .last,.rst-content .danger>:last-child,.rst-content .error .last,.rst-content .error>:last-child,.rst-content .hint .last,.rst-content .hint>:last-child,.rst-content .important .last,.rst-content .important>:last-child,.rst-content .note .last,.rst-content .note>:last-child,.rst-content .seealso .last,.rst-content .seealso>:last-child,.rst-content .tip .last,.rst-content .tip>:last-child,.rst-content .warning .last,.rst-content .warning>:last-child{margin-bottom:0}.rst-content .admonition-title:before{margin-right:4px}.rst-content .admonition table{border-color:rgba(0,0,0,.1)}.rst-content .admonition table td,.rst-content .admonition table th{background:transparent!important;border-color:rgba(0,0,0,.1)!important}.rst-content .section ol.loweralpha,.rst-content .section ol.loweralpha>li,.rst-content .toctree-wrapper ol.loweralpha,.rst-content .toctree-wrapper ol.loweralpha>li,.rst-content section ol.loweralpha,.rst-content section ol.loweralpha>li{list-style:lower-alpha}.rst-content .section ol.upperalpha,.rst-content .section ol.upperalpha>li,.rst-content .toctree-wrapper ol.upperalpha,.rst-content .toctree-wrapper ol.upperalpha>li,.rst-content section ol.upperalpha,.rst-content section ol.upperalpha>li{list-style:upper-alpha}.rst-content .section ol li>*,.rst-content .section ul li>*,.rst-content .toctree-wrapper ol li>*,.rst-content .toctree-wrapper ul li>*,.rst-content section ol li>*,.rst-content section ul li>*{margin-top:12px;margin-bottom:12px}.rst-content .section ol li>:first-child,.rst-content .section ul li>:first-child,.rst-content .toctree-wrapper ol li>:first-child,.rst-content .toctree-wrapper ul li>:first-child,.rst-content section ol li>:first-child,.rst-content section ul li>:first-child{margin-top:0}.rst-content .section ol li>p,.rst-content .section ol li>p:last-child,.rst-content .section ul li>p,.rst-content .section ul li>p:last-child,.rst-content .toctree-wrapper ol li>p,.rst-content .toctree-wrapper ol li>p:last-child,.rst-content .toctree-wrapper ul li>p,.rst-content .toctree-wrapper ul li>p:last-child,.rst-content section ol li>p,.rst-content section ol li>p:last-child,.rst-content section ul li>p,.rst-content section ul li>p:last-child{margin-bottom:12px}.rst-content .section ol li>p:only-child,.rst-content .section ol li>p:only-child:last-child,.rst-content .section ul li>p:only-child,.rst-content .section ul li>p:only-child:last-child,.rst-content .toctree-wrapper ol li>p:only-child,.rst-content .toctree-wrapper ol li>p:only-child:last-child,.rst-content .toctree-wrapper ul li>p:only-child,.rst-content .toctree-wrapper ul li>p:only-child:last-child,.rst-content section ol li>p:only-child,.rst-content section ol li>p:only-child:last-child,.rst-content section ul li>p:only-child,.rst-content section ul li>p:only-child:last-child{margin-bottom:0}.rst-content .section ol li>ol,.rst-content .section ol li>ul,.rst-content .section ul li>ol,.rst-content .section ul li>ul,.rst-content .toctree-wrapper ol li>ol,.rst-content .toctree-wrapper ol li>ul,.rst-content .toctree-wrapper ul li>ol,.rst-content .toctree-wrapper ul li>ul,.rst-content section ol li>ol,.rst-content section ol li>ul,.rst-content section ul li>ol,.rst-content section ul li>ul{margin-bottom:12px}.rst-content .section ol.simple li>*,.rst-content .section ol.simple li ol,.rst-content .section ol.simple li ul,.rst-content .section ul.simple li>*,.rst-content .section ul.simple li ol,.rst-content .section ul.simple li ul,.rst-content .toctree-wrapper ol.simple li>*,.rst-content .toctree-wrapper ol.simple li ol,.rst-content .toctree-wrapper ol.simple li ul,.rst-content .toctree-wrapper ul.simple li>*,.rst-content .toctree-wrapper ul.simple li ol,.rst-content .toctree-wrapper ul.simple li ul,.rst-content section ol.simple li>*,.rst-content section ol.simple li ol,.rst-content section ol.simple li ul,.rst-content section ul.simple li>*,.rst-content section ul.simple li ol,.rst-content section ul.simple li ul{margin-top:0;margin-bottom:0}.rst-content .line-block{margin-left:0;margin-bottom:24px;line-height:24px}.rst-content .line-block .line-block{margin-left:24px;margin-bottom:0}.rst-content .topic-title{font-weight:700;margin-bottom:12px}.rst-content .toc-backref{color:#404040}.rst-content .align-right{float:right;margin:0 0 24px 24px}.rst-content .align-left{float:left;margin:0 24px 24px 0}.rst-content .align-center{margin:auto}.rst-content .align-center:not(table){display:block}.rst-content .code-block-caption .headerlink,.rst-content .eqno .headerlink,.rst-content .toctree-wrapper>p.caption .headerlink,.rst-content dl dt .headerlink,.rst-content h1 .headerlink,.rst-content h2 .headerlink,.rst-content h3 .headerlink,.rst-content h4 .headerlink,.rst-content h5 .headerlink,.rst-content h6 .headerlink,.rst-content p.caption .headerlink,.rst-content p .headerlink,.rst-content table>caption .headerlink{opacity:0;font-size:14px;font-family:FontAwesome;margin-left:.5em}.rst-content .code-block-caption .headerlink:focus,.rst-content .code-block-caption:hover .headerlink,.rst-content .eqno .headerlink:focus,.rst-content .eqno:hover .headerlink,.rst-content .toctree-wrapper>p.caption .headerlink:focus,.rst-content .toctree-wrapper>p.caption:hover .headerlink,.rst-content dl dt .headerlink:focus,.rst-content dl dt:hover .headerlink,.rst-content h1 .headerlink:focus,.rst-content h1:hover .headerlink,.rst-content h2 .headerlink:focus,.rst-content h2:hover .headerlink,.rst-content h3 .headerlink:focus,.rst-content h3:hover .headerlink,.rst-content h4 .headerlink:focus,.rst-content h4:hover .headerlink,.rst-content h5 .headerlink:focus,.rst-content h5:hover .headerlink,.rst-content h6 .headerlink:focus,.rst-content h6:hover .headerlink,.rst-content p.caption .headerlink:focus,.rst-content p.caption:hover .headerlink,.rst-content p .headerlink:focus,.rst-content p:hover .headerlink,.rst-content table>caption .headerlink:focus,.rst-content table>caption:hover .headerlink{opacity:1}.rst-content p a{overflow-wrap:anywhere}.rst-content .wy-table td p,.rst-content .wy-table td ul,.rst-content .wy-table th p,.rst-content .wy-table th ul,.rst-content table.docutils td p,.rst-content table.docutils td ul,.rst-content table.docutils th p,.rst-content table.docutils th ul,.rst-content table.field-list td p,.rst-content table.field-list td ul,.rst-content table.field-list th p,.rst-content table.field-list th ul{font-size:inherit}.rst-content .btn:focus{outline:2px solid}.rst-content table>caption .headerlink:after{font-size:12px}.rst-content .centered{text-align:center}.rst-content .sidebar{float:right;width:40%;display:block;margin:0 0 24px 24px;padding:24px;background:#f3f6f6;border:1px solid #e1e4e5}.rst-content .sidebar dl,.rst-content .sidebar p,.rst-content .sidebar ul{font-size:90%}.rst-content .sidebar .last,.rst-content .sidebar>:last-child{margin-bottom:0}.rst-content .sidebar .sidebar-title{display:block;font-family:Roboto Slab,ff-tisa-web-pro,Georgia,Arial,sans-serif;font-weight:700;background:#e1e4e5;padding:6px 12px;margin:-24px -24px 24px;font-size:100%}.rst-content .highlighted{background:#f1c40f;box-shadow:0 0 0 2px #f1c40f;display:inline;font-weight:700}.rst-content .citation-reference,.rst-content .footnote-reference{vertical-align:baseline;position:relative;top:-.4em;line-height:0;font-size:90%}.rst-content .citation-reference>span.fn-bracket,.rst-content .footnote-reference>span.fn-bracket{display:none}.rst-content .hlist{width:100%}.rst-content dl dt span.classifier:before{content:" : "}.rst-content dl dt span.classifier-delimiter{display:none!important}html.writer-html4 .rst-content table.docutils.citation,html.writer-html4 .rst-content table.docutils.footnote{background:none;border:none}html.writer-html4 .rst-content table.docutils.citation td,html.writer-html4 .rst-content table.docutils.citation tr,html.writer-html4 .rst-content table.docutils.footnote td,html.writer-html4 .rst-content table.docutils.footnote tr{border:none;background-color:transparent!important;white-space:normal}html.writer-html4 .rst-content table.docutils.citation td.label,html.writer-html4 .rst-content table.docutils.footnote td.label{padding-left:0;padding-right:0;vertical-align:top}html.writer-html5 .rst-content dl.citation,html.writer-html5 .rst-content dl.field-list,html.writer-html5 .rst-content dl.footnote{display:grid;grid-template-columns:auto minmax(80%,95%)}html.writer-html5 .rst-content dl.citation>dt,html.writer-html5 .rst-content dl.field-list>dt,html.writer-html5 .rst-content dl.footnote>dt{display:inline-grid;grid-template-columns:max-content auto}html.writer-html5 .rst-content aside.citation,html.writer-html5 .rst-content aside.footnote,html.writer-html5 .rst-content div.citation{display:grid;grid-template-columns:auto auto minmax(.65rem,auto) minmax(40%,95%)}html.writer-html5 .rst-content aside.citation>span.label,html.writer-html5 .rst-content aside.footnote>span.label,html.writer-html5 .rst-content div.citation>span.label{grid-column-start:1;grid-column-end:2}html.writer-html5 .rst-content aside.citation>span.backrefs,html.writer-html5 .rst-content aside.footnote>span.backrefs,html.writer-html5 .rst-content div.citation>span.backrefs{grid-column-start:2;grid-column-end:3;grid-row-start:1;grid-row-end:3}html.writer-html5 .rst-content aside.citation>p,html.writer-html5 .rst-content aside.footnote>p,html.writer-html5 .rst-content div.citation>p{grid-column-start:4;grid-column-end:5}html.writer-html5 .rst-content dl.citation,html.writer-html5 .rst-content dl.field-list,html.writer-html5 .rst-content dl.footnote{margin-bottom:24px}html.writer-html5 .rst-content dl.citation>dt,html.writer-html5 .rst-content dl.field-list>dt,html.writer-html5 .rst-content dl.footnote>dt{padding-left:1rem}html.writer-html5 .rst-content dl.citation>dd,html.writer-html5 .rst-content dl.citation>dt,html.writer-html5 .rst-content dl.field-list>dd,html.writer-html5 .rst-content dl.field-list>dt,html.writer-html5 .rst-content dl.footnote>dd,html.writer-html5 .rst-content dl.footnote>dt{margin-bottom:0}html.writer-html5 .rst-content dl.citation,html.writer-html5 .rst-content dl.footnote{font-size:.9rem}html.writer-html5 .rst-content dl.citation>dt,html.writer-html5 .rst-content dl.footnote>dt{margin:0 .5rem .5rem 0;line-height:1.2rem;word-break:break-all;font-weight:400}html.writer-html5 .rst-content dl.citation>dt>span.brackets:before,html.writer-html5 .rst-content dl.footnote>dt>span.brackets:before{content:"["}html.writer-html5 .rst-content dl.citation>dt>span.brackets:after,html.writer-html5 .rst-content dl.footnote>dt>span.brackets:after{content:"]"}html.writer-html5 .rst-content dl.citation>dt>span.fn-backref,html.writer-html5 .rst-content dl.footnote>dt>span.fn-backref{text-align:left;font-style:italic;margin-left:.65rem;word-break:break-word;word-spacing:-.1rem;max-width:5rem}html.writer-html5 .rst-content dl.citation>dt>span.fn-backref>a,html.writer-html5 .rst-content dl.footnote>dt>span.fn-backref>a{word-break:keep-all}html.writer-html5 .rst-content dl.citation>dt>span.fn-backref>a:not(:first-child):before,html.writer-html5 .rst-content dl.footnote>dt>span.fn-backref>a:not(:first-child):before{content:" "}html.writer-html5 .rst-content dl.citation>dd,html.writer-html5 .rst-content dl.footnote>dd{margin:0 0 .5rem;line-height:1.2rem}html.writer-html5 .rst-content dl.citation>dd p,html.writer-html5 .rst-content dl.footnote>dd p{font-size:.9rem}html.writer-html5 .rst-content aside.citation,html.writer-html5 .rst-content aside.footnote,html.writer-html5 .rst-content div.citation{padding-left:1rem;padding-right:1rem;font-size:.9rem;line-height:1.2rem}html.writer-html5 .rst-content aside.citation p,html.writer-html5 .rst-content aside.footnote p,html.writer-html5 .rst-content div.citation p{font-size:.9rem;line-height:1.2rem;margin-bottom:12px}html.writer-html5 .rst-content aside.citation span.backrefs,html.writer-html5 .rst-content aside.footnote span.backrefs,html.writer-html5 .rst-content div.citation span.backrefs{text-align:left;font-style:italic;margin-left:.65rem;word-break:break-word;word-spacing:-.1rem;max-width:5rem}html.writer-html5 .rst-content aside.citation span.backrefs>a,html.writer-html5 .rst-content aside.footnote span.backrefs>a,html.writer-html5 .rst-content div.citation span.backrefs>a{word-break:keep-all}html.writer-html5 .rst-content aside.citation span.backrefs>a:not(:first-child):before,html.writer-html5 .rst-content aside.footnote span.backrefs>a:not(:first-child):before,html.writer-html5 .rst-content div.citation span.backrefs>a:not(:first-child):before{content:" "}html.writer-html5 .rst-content aside.citation span.label,html.writer-html5 .rst-content aside.footnote span.label,html.writer-html5 .rst-content div.citation span.label{line-height:1.2rem}html.writer-html5 .rst-content aside.citation-list,html.writer-html5 .rst-content aside.footnote-list,html.writer-html5 .rst-content div.citation-list{margin-bottom:24px}html.writer-html5 .rst-content dl.option-list kbd{font-size:.9rem}.rst-content table.docutils.footnote,html.writer-html4 .rst-content table.docutils.citation,html.writer-html5 .rst-content aside.footnote,html.writer-html5 .rst-content aside.footnote-list aside.footnote,html.writer-html5 .rst-content div.citation-list>div.citation,html.writer-html5 .rst-content dl.citation,html.writer-html5 .rst-content dl.footnote{color:grey}.rst-content table.docutils.footnote code,.rst-content table.docutils.footnote tt,html.writer-html4 .rst-content table.docutils.citation code,html.writer-html4 .rst-content table.docutils.citation tt,html.writer-html5 .rst-content aside.footnote-list aside.footnote code,html.writer-html5 .rst-content aside.footnote-list aside.footnote tt,html.writer-html5 .rst-content aside.footnote code,html.writer-html5 .rst-content aside.footnote tt,html.writer-html5 .rst-content div.citation-list>div.citation code,html.writer-html5 .rst-content div.citation-list>div.citation tt,html.writer-html5 .rst-content dl.citation code,html.writer-html5 .rst-content dl.citation tt,html.writer-html5 .rst-content dl.footnote code,html.writer-html5 .rst-content dl.footnote tt{color:#555}.rst-content .wy-table-responsive.citation,.rst-content .wy-table-responsive.footnote{margin-bottom:0}.rst-content .wy-table-responsive.citation+:not(.citation),.rst-content .wy-table-responsive.footnote+:not(.footnote){margin-top:24px}.rst-content .wy-table-responsive.citation:last-child,.rst-content .wy-table-responsive.footnote:last-child{margin-bottom:24px}.rst-content table.docutils th{border-color:#e1e4e5}html.writer-html5 .rst-content table.docutils th{border:1px solid #e1e4e5}html.writer-html5 .rst-content table.docutils td>p,html.writer-html5 .rst-content table.docutils th>p{line-height:1rem;margin-bottom:0;font-size:.9rem}.rst-content table.docutils td .last,.rst-content table.docutils td .last>:last-child{margin-bottom:0}.rst-content table.field-list,.rst-content table.field-list td{border:none}.rst-content table.field-list td p{line-height:inherit}.rst-content table.field-list td>strong{display:inline-block}.rst-content table.field-list .field-name{padding-right:10px;text-align:left;white-space:nowrap}.rst-content table.field-list .field-body{text-align:left}.rst-content code,.rst-content tt{color:#000;font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;padding:2px 5px}.rst-content code big,.rst-content code em,.rst-content tt big,.rst-content tt em{font-size:100%!important;line-height:normal}.rst-content code.literal,.rst-content tt.literal{color:#e74c3c;white-space:normal}.rst-content code.xref,.rst-content tt.xref,a .rst-content code,a .rst-content tt{font-weight:700;color:#404040;overflow-wrap:normal}.rst-content kbd,.rst-content pre,.rst-content samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace}.rst-content a code,.rst-content a tt{color:#2980b9}.rst-content dl{margin-bottom:24px}.rst-content dl dt{font-weight:700;margin-bottom:12px}.rst-content dl ol,.rst-content dl p,.rst-content dl table,.rst-content dl ul{margin-bottom:12px}.rst-content dl dd{margin:0 0 12px 24px;line-height:24px}.rst-content dl dd>ol:last-child,.rst-content dl dd>p:last-child,.rst-content dl dd>table:last-child,.rst-content dl dd>ul:last-child{margin-bottom:0}html.writer-html4 .rst-content dl:not(.docutils),html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple){margin-bottom:24px}html.writer-html4 .rst-content dl:not(.docutils)>dt,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt{display:table;margin:6px 0;font-size:90%;line-height:normal;background:#e7f2fa;color:#2980b9;border-top:3px solid #6ab0de;padding:6px;position:relative}html.writer-html4 .rst-content dl:not(.docutils)>dt:before,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt:before{color:#6ab0de}html.writer-html4 .rst-content dl:not(.docutils)>dt .headerlink,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt .headerlink{color:#404040;font-size:100%!important}html.writer-html4 .rst-content dl:not(.docutils) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt{margin-bottom:6px;border:none;border-left:3px solid #ccc;background:#f0f0f0;color:#555}html.writer-html4 .rst-content dl:not(.docutils) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt .headerlink,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) dl:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt .headerlink{color:#404040;font-size:100%!important}html.writer-html4 .rst-content dl:not(.docutils)>dt:first-child,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple)>dt:first-child{margin-top:0}html.writer-html4 .rst-content dl:not(.docutils) code.descclassname,html.writer-html4 .rst-content dl:not(.docutils) code.descname,html.writer-html4 .rst-content dl:not(.docutils) tt.descclassname,html.writer-html4 .rst-content dl:not(.docutils) tt.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) code.descclassname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) code.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) tt.descclassname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) tt.descname{background-color:transparent;border:none;padding:0;font-size:100%!important}html.writer-html4 .rst-content dl:not(.docutils) code.descname,html.writer-html4 .rst-content dl:not(.docutils) tt.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) code.descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) tt.descname{font-weight:700}html.writer-html4 .rst-content dl:not(.docutils) .optional,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .optional{display:inline-block;padding:0 4px;color:#000;font-weight:700}html.writer-html4 .rst-content dl:not(.docutils) .property,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .property{display:inline-block;padding-right:8px;max-width:100%}html.writer-html4 .rst-content dl:not(.docutils) .k,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .k{font-style:italic}html.writer-html4 .rst-content dl:not(.docutils) .descclassname,html.writer-html4 .rst-content dl:not(.docutils) .descname,html.writer-html4 .rst-content dl:not(.docutils) .sig-name,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .descclassname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .descname,html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.citation):not(.glossary):not(.simple) .sig-name{font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,Courier,monospace;color:#000}.rst-content .viewcode-back,.rst-content .viewcode-link{display:inline-block;color:#27ae60;font-size:80%;padding-left:24px}.rst-content .viewcode-back{display:block;float:right}.rst-content p.rubric{margin-bottom:12px;font-weight:700}.rst-content code.download,.rst-content tt.download{background:inherit;padding:inherit;font-weight:400;font-family:inherit;font-size:inherit;color:inherit;border:inherit;white-space:inherit}.rst-content code.download span:first-child,.rst-content tt.download span:first-child{-webkit-font-smoothing:subpixel-antialiased}.rst-content code.download span:first-child:before,.rst-content tt.download span:first-child:before{margin-right:4px}.rst-content .guilabel,.rst-content .menuselection{font-size:80%;font-weight:700;border-radius:4px;padding:2.4px 6px;margin:auto 2px}.rst-content .guilabel,.rst-content .menuselection{border:1px solid #7fbbe3;background:#e7f2fa}.rst-content :not(dl.option-list)>:not(dt):not(kbd):not(.kbd)>.kbd,.rst-content :not(dl.option-list)>:not(dt):not(kbd):not(.kbd)>kbd{color:inherit;font-size:80%;background-color:#fff;border:1px solid #a6a6a6;border-radius:4px;box-shadow:0 2px grey;padding:2.4px 6px;margin:auto 0}.rst-content .versionmodified{font-style:italic}@media screen and (max-width:480px){.rst-content .sidebar{width:100%}}span[id*=MathJax-Span]{color:#404040}.math{text-align:center}@font-face{font-family:Lato;src:url(fonts/lato-normal.woff2?bd03a2cc277bbbc338d464e679fe9942) format("woff2"),url(fonts/lato-normal.woff?27bd77b9162d388cb8d4c4217c7c5e2a) format("woff");font-weight:400;font-style:normal;font-display:block}@font-face{font-family:Lato;src:url(fonts/lato-bold.woff2?cccb897485813c7c256901dbca54ecf2) format("woff2"),url(fonts/lato-bold.woff?d878b6c29b10beca227e9eef4246111b) format("woff");font-weight:700;font-style:normal;font-display:block}@font-face{font-family:Lato;src:url(fonts/lato-bold-italic.woff2?0b6bb6725576b072c5d0b02ecdd1900d) format("woff2"),url(fonts/lato-bold-italic.woff?9c7e4e9eb485b4a121c760e61bc3707c) format("woff");font-weight:700;font-style:italic;font-display:block}@font-face{font-family:Lato;src:url(fonts/lato-normal-italic.woff2?4eb103b4d12be57cb1d040ed5e162e9d) format("woff2"),url(fonts/lato-normal-italic.woff?f28f2d6482446544ef1ea1ccc6dd5892) format("woff");font-weight:400;font-style:italic;font-display:block}@font-face{font-family:Roboto Slab;font-style:normal;font-weight:400;src:url(fonts/Roboto-Slab-Regular.woff2?7abf5b8d04d26a2cafea937019bca958) format("woff2"),url(fonts/Roboto-Slab-Regular.woff?c1be9284088d487c5e3ff0a10a92e58c) format("woff");font-display:block}@font-face{font-family:Roboto Slab;font-style:normal;font-weight:700;src:url(fonts/Roboto-Slab-Bold.woff2?9984f4a9bda09be08e83f2506954adbe) format("woff2"),url(fonts/Roboto-Slab-Bold.woff?bed5564a116b05148e3b3bea6fb1162a) format("woff");font-display:block} \ No newline at end of file diff --git a/_static/doctools.js b/_static/doctools.js new file mode 100644 index 0000000..4d67807 --- /dev/null +++ b/_static/doctools.js @@ -0,0 +1,156 @@ +/* + * doctools.js + * ~~~~~~~~~~~ + * + * Base JavaScript utilities for all Sphinx HTML documentation. + * + * :copyright: Copyright 2007-2024 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ +"use strict"; + +const BLACKLISTED_KEY_CONTROL_ELEMENTS = new Set([ + "TEXTAREA", + "INPUT", + "SELECT", + "BUTTON", +]); + +const _ready = (callback) => { + if (document.readyState !== "loading") { + callback(); + } else { + document.addEventListener("DOMContentLoaded", callback); + } +}; + +/** + * Small JavaScript module for the documentation. + */ +const Documentation = { + init: () => { + Documentation.initDomainIndexTable(); + Documentation.initOnKeyListeners(); + }, + + /** + * i18n support + */ + TRANSLATIONS: {}, + PLURAL_EXPR: (n) => (n === 1 ? 0 : 1), + LOCALE: "unknown", + + // gettext and ngettext don't access this so that the functions + // can safely bound to a different name (_ = Documentation.gettext) + gettext: (string) => { + const translated = Documentation.TRANSLATIONS[string]; + switch (typeof translated) { + case "undefined": + return string; // no translation + case "string": + return translated; // translation exists + default: + return translated[0]; // (singular, plural) translation tuple exists + } + }, + + ngettext: (singular, plural, n) => { + const translated = Documentation.TRANSLATIONS[singular]; + if (typeof translated !== "undefined") + return translated[Documentation.PLURAL_EXPR(n)]; + return n === 1 ? singular : plural; + }, + + addTranslations: (catalog) => { + Object.assign(Documentation.TRANSLATIONS, catalog.messages); + Documentation.PLURAL_EXPR = new Function( + "n", + `return (${catalog.plural_expr})` + ); + Documentation.LOCALE = catalog.locale; + }, + + /** + * helper function to focus on search bar + */ + focusSearchBar: () => { + document.querySelectorAll("input[name=q]")[0]?.focus(); + }, + + /** + * Initialise the domain index toggle buttons + */ + initDomainIndexTable: () => { + const toggler = (el) => { + const idNumber = el.id.substr(7); + const toggledRows = document.querySelectorAll(`tr.cg-${idNumber}`); + if (el.src.substr(-9) === "minus.png") { + el.src = `${el.src.substr(0, el.src.length - 9)}plus.png`; + toggledRows.forEach((el) => (el.style.display = "none")); + } else { + el.src = `${el.src.substr(0, el.src.length - 8)}minus.png`; + toggledRows.forEach((el) => (el.style.display = "")); + } + }; + + const togglerElements = document.querySelectorAll("img.toggler"); + togglerElements.forEach((el) => + el.addEventListener("click", (event) => toggler(event.currentTarget)) + ); + togglerElements.forEach((el) => (el.style.display = "")); + if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) togglerElements.forEach(toggler); + }, + + initOnKeyListeners: () => { + // only install a listener if it is really needed + if ( + !DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS && + !DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS + ) + return; + + document.addEventListener("keydown", (event) => { + // bail for input elements + if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return; + // bail with special keys + if (event.altKey || event.ctrlKey || event.metaKey) return; + + if (!event.shiftKey) { + switch (event.key) { + case "ArrowLeft": + if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; + + const prevLink = document.querySelector('link[rel="prev"]'); + if (prevLink && prevLink.href) { + window.location.href = prevLink.href; + event.preventDefault(); + } + break; + case "ArrowRight": + if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) break; + + const nextLink = document.querySelector('link[rel="next"]'); + if (nextLink && nextLink.href) { + window.location.href = nextLink.href; + event.preventDefault(); + } + break; + } + } + + // some keyboard layouts may need Shift to get / + switch (event.key) { + case "/": + if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) break; + Documentation.focusSearchBar(); + event.preventDefault(); + } + }); + }, +}; + +// quick alias for translations +const _ = Documentation.gettext; + +_ready(Documentation.init); diff --git a/_static/documentation_options.js b/_static/documentation_options.js new file mode 100644 index 0000000..89435bb --- /dev/null +++ b/_static/documentation_options.js @@ -0,0 +1,13 @@ +const DOCUMENTATION_OPTIONS = { + VERSION: '1.0.0', + LANGUAGE: 'en', + COLLAPSE_INDEX: false, + BUILDER: 'html', + FILE_SUFFIX: '.html', + LINK_SUFFIX: '.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt', + NAVIGATION_WITH_KEYS: false, + SHOW_SEARCH_SUMMARY: true, + ENABLE_SEARCH_SHORTCUTS: true, +}; \ No newline at end of file diff --git a/_static/file.png b/_static/file.png new file mode 100644 index 0000000..a858a41 Binary files /dev/null and b/_static/file.png differ diff --git a/_static/jquery.js b/_static/jquery.js new file mode 100644 index 0000000..c4c6022 --- /dev/null +++ b/_static/jquery.js @@ -0,0 +1,2 @@ +/*! jQuery v3.6.0 | (c) OpenJS Foundation and other contributors | jquery.org/license */ +!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(C,e){"use strict";var t=[],r=Object.getPrototypeOf,s=t.slice,g=t.flat?function(e){return t.flat.call(e)}:function(e){return t.concat.apply([],e)},u=t.push,i=t.indexOf,n={},o=n.toString,v=n.hasOwnProperty,a=v.toString,l=a.call(Object),y={},m=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType&&"function"!=typeof e.item},x=function(e){return null!=e&&e===e.window},E=C.document,c={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||E).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.6.0",S=function(e,t){return new S.fn.init(e,t)};function p(e){var t=!!e&&"length"in e&&e.length,n=w(e);return!m(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp(F),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+F),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\[\\da-fA-F]{1,6}"+M+"?|\\\\([^\\r\\n\\f])","g"),ne=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=O.call(p.childNodes),p.childNodes),t[p.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&(T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!N[t+" "]&&(!v||!v.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&(U.test(t)||z.test(t))){(f=ee.test(t)&&ye(e.parentNode)||e)===e&&d.scope||((s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=S)),o=(l=h(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+xe(l[o]);c=l.join(",")}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){N(t,!0)}finally{s===S&&e.removeAttribute("id")}}}return g(t.replace($,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[S]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e&&e.namespaceURI,n=e&&(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:p;return r!=C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),p!=C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),d.scope=ce(function(e){return a.appendChild(e).appendChild(C.createElement("div")),"undefined"!=typeof e.querySelectorAll&&!e.querySelectorAll(":scope fieldset div").length}),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=S,!C.getElementsByName||!C.getElementsByName(S).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){var t;a.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+S+"-]").length||v.push("~="),(t=C.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||v.push("\\["+M+"*name"+M+"*="+M+"*(?:''|\"\")"),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+S+"+*").length||v.push(".#.+[+~]"),e.querySelectorAll("\\\f"),v.push("[\\r\\n\\f]")}),ce(function(e){e.innerHTML="";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",F)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test(a.compareDocumentPosition),y=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},j=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e==C||e.ownerDocument==p&&y(p,e)?-1:t==C||t.ownerDocument==p&&y(p,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e==C?-1:t==C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]==p?-1:s[r]==p?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if(T(e),d.matchesSelector&&E&&!N[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){N(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=m[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&m(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,n,r){return m(n)?S.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?S.grep(e,function(e){return e===n!==r}):"string"!=typeof n?S.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(S.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||D,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:q.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof S?t[0]:t,S.merge(this,S.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),N.test(r[1])&&S.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(S):S.makeArray(e,this)}).prototype=S.fn,D=S(E);var L=/^(?:parents|prev(?:Until|All))/,H={children:!0,contents:!0,next:!0,prev:!0};function O(e,t){while((e=e[t])&&1!==e.nodeType);return e}S.fn.extend({has:function(e){var t=S(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i;ce=E.createDocumentFragment().appendChild(E.createElement("div")),(fe=E.createElement("input")).setAttribute("type","radio"),fe.setAttribute("checked","checked"),fe.setAttribute("name","t"),ce.appendChild(fe),y.checkClone=ce.cloneNode(!0).cloneNode(!0).lastChild.checked,ce.innerHTML="",y.noCloneChecked=!!ce.cloneNode(!0).lastChild.defaultValue,ce.innerHTML="",y.option=!!ce.lastChild;var ge={thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};function ve(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&A(e,t)?S.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;n",""]);var me=/<|&#?\w+;/;function xe(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d\s*$/g;function je(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&S(e).children("tbody")[0]||e}function De(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function qe(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Le(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(Y.hasData(e)&&(s=Y.get(e).events))for(i in Y.remove(t,"handle events"),s)for(n=0,r=s[i].length;n").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var _t,zt=[],Ut=/(=)\?(?=&|$)|\?\?/;S.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=zt.pop()||S.expando+"_"+wt.guid++;return this[e]=!0,e}}),S.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Ut.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Ut.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Ut,"$1"+r):!1!==e.jsonp&&(e.url+=(Tt.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||S.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?S(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,zt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),"script"}),y.createHTMLDocument=((_t=E.implementation.createHTMLDocument("").body).innerHTML="
",2===_t.childNodes.length),S.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument("")).createElement("base")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=N.exec(e))?[t.createElement(i[1])]:(i=xe([e],t,o),o&&o.length&&S(o).remove(),S.merge([],i.childNodes)));var r,i,o},S.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(S.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},S.expr.pseudos.animated=function(t){return S.grep(S.timers,function(e){return t===e.elem}).length},S.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=S.css(e,"position"),c=S(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=S.css(e,"top"),u=S.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,S.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},S.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){S.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===S.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===S.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=S(e).offset()).top+=S.css(e,"borderTopWidth",!0),i.left+=S.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-S.css(r,"marginTop",!0),left:t.left-i.left-S.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===S.css(e,"position"))e=e.offsetParent;return e||re})}}),S.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;S.fn[t]=function(e){return $(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),S.each(["top","left"],function(e,n){S.cssHooks[n]=Fe(y.pixelPosition,function(e,t){if(t)return t=We(e,n),Pe.test(t)?S(e).position()[n]+"px":t})}),S.each({Height:"height",Width:"width"},function(a,s){S.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){S.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return $(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?S.css(e,t,i):S.style(e,t,n,i)},s,n?e:void 0,n)}})}),S.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){S.fn[t]=function(e){return this.on(t,e)}}),S.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),S.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){S.fn[n]=function(e,t){return 0",d.insertBefore(c.lastChild,d.firstChild)}function d(){var a=y.elements;return"string"==typeof a?a.split(" "):a}function e(a,b){var c=y.elements;"string"!=typeof c&&(c=c.join(" ")),"string"!=typeof a&&(a=a.join(" ")),y.elements=c+" "+a,j(b)}function f(a){var b=x[a[v]];return b||(b={},w++,a[v]=w,x[w]=b),b}function g(a,c,d){if(c||(c=b),q)return c.createElement(a);d||(d=f(c));var e;return e=d.cache[a]?d.cache[a].cloneNode():u.test(a)?(d.cache[a]=d.createElem(a)).cloneNode():d.createElem(a),!e.canHaveChildren||t.test(a)||e.tagUrn?e:d.frag.appendChild(e)}function h(a,c){if(a||(a=b),q)return a.createDocumentFragment();c=c||f(a);for(var e=c.frag.cloneNode(),g=0,h=d(),i=h.length;i>g;g++)e.createElement(h[g]);return e}function i(a,b){b.cache||(b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag()),a.createElement=function(c){return y.shivMethods?g(c,a,b):b.createElem(c)},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+d().join().replace(/[\w\-:]+/g,function(a){return b.createElem(a),b.frag.createElement(a),'c("'+a+'")'})+");return n}")(y,b.frag)}function j(a){a||(a=b);var d=f(a);return!y.shivCSS||p||d.hasCSS||(d.hasCSS=!!c(a,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),q||i(a,d),a}function k(a){for(var b,c=a.getElementsByTagName("*"),e=c.length,f=RegExp("^(?:"+d().join("|")+")$","i"),g=[];e--;)b=c[e],f.test(b.nodeName)&&g.push(b.applyElement(l(b)));return g}function l(a){for(var b,c=a.attributes,d=c.length,e=a.ownerDocument.createElement(A+":"+a.nodeName);d--;)b=c[d],b.specified&&e.setAttribute(b.nodeName,b.nodeValue);return e.style.cssText=a.style.cssText,e}function m(a){for(var b,c=a.split("{"),e=c.length,f=RegExp("(^|[\\s,>+~])("+d().join("|")+")(?=[[\\s,>+~#.:]|$)","gi"),g="$1"+A+"\\:$2";e--;)b=c[e]=c[e].split("}"),b[b.length-1]=b[b.length-1].replace(f,g),c[e]=b.join("}");return c.join("{")}function n(a){for(var b=a.length;b--;)a[b].removeNode()}function o(a){function b(){clearTimeout(g._removeSheetTimer),d&&d.removeNode(!0),d=null}var d,e,g=f(a),h=a.namespaces,i=a.parentWindow;return!B||a.printShived?a:("undefined"==typeof h[A]&&h.add(A),i.attachEvent("onbeforeprint",function(){b();for(var f,g,h,i=a.styleSheets,j=[],l=i.length,n=Array(l);l--;)n[l]=i[l];for(;h=n.pop();)if(!h.disabled&&z.test(h.media)){try{f=h.imports,g=f.length}catch(o){g=0}for(l=0;g>l;l++)n.push(f[l]);try{j.push(h.cssText)}catch(o){}}j=m(j.reverse().join("")),e=k(a),d=c(a,j)}),i.attachEvent("onafterprint",function(){n(e),clearTimeout(g._removeSheetTimer),g._removeSheetTimer=setTimeout(b,500)}),a.printShived=!0,a)}var p,q,r="3.7.3",s=a.html5||{},t=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,u=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,v="_html5shiv",w=0,x={};!function(){try{var a=b.createElement("a");a.innerHTML="",p="hidden"in a,q=1==a.childNodes.length||function(){b.createElement("a");var a=b.createDocumentFragment();return"undefined"==typeof a.cloneNode||"undefined"==typeof a.createDocumentFragment||"undefined"==typeof a.createElement}()}catch(c){p=!0,q=!0}}();var y={elements:s.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:r,shivCSS:s.shivCSS!==!1,supportsUnknownElements:q,shivMethods:s.shivMethods!==!1,type:"default",shivDocument:j,createElement:g,createDocumentFragment:h,addElements:e};a.html5=y,j(b);var z=/^$|\b(?:all|print)\b/,A="html5shiv",B=!q&&function(){var c=b.documentElement;return!("undefined"==typeof b.namespaces||"undefined"==typeof b.parentWindow||"undefined"==typeof c.applyElement||"undefined"==typeof c.removeNode||"undefined"==typeof a.attachEvent)}();y.type+=" print",y.shivPrint=o,o(b),"object"==typeof module&&module.exports&&(module.exports=y)}("undefined"!=typeof window?window:this,document); \ No newline at end of file diff --git a/_static/js/html5shiv.min.js b/_static/js/html5shiv.min.js new file mode 100644 index 0000000..cd1c674 --- /dev/null +++ b/_static/js/html5shiv.min.js @@ -0,0 +1,4 @@ +/** +* @preserve HTML5 Shiv 3.7.3 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed +*/ +!function(a,b){function c(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x",d.insertBefore(c.lastChild,d.firstChild)}function d(){var a=t.elements;return"string"==typeof a?a.split(" "):a}function e(a,b){var c=t.elements;"string"!=typeof c&&(c=c.join(" ")),"string"!=typeof a&&(a=a.join(" ")),t.elements=c+" "+a,j(b)}function f(a){var b=s[a[q]];return b||(b={},r++,a[q]=r,s[r]=b),b}function g(a,c,d){if(c||(c=b),l)return c.createElement(a);d||(d=f(c));var e;return e=d.cache[a]?d.cache[a].cloneNode():p.test(a)?(d.cache[a]=d.createElem(a)).cloneNode():d.createElem(a),!e.canHaveChildren||o.test(a)||e.tagUrn?e:d.frag.appendChild(e)}function h(a,c){if(a||(a=b),l)return a.createDocumentFragment();c=c||f(a);for(var e=c.frag.cloneNode(),g=0,h=d(),i=h.length;i>g;g++)e.createElement(h[g]);return e}function i(a,b){b.cache||(b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag()),a.createElement=function(c){return t.shivMethods?g(c,a,b):b.createElem(c)},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+d().join().replace(/[\w\-:]+/g,function(a){return b.createElem(a),b.frag.createElement(a),'c("'+a+'")'})+");return n}")(t,b.frag)}function j(a){a||(a=b);var d=f(a);return!t.shivCSS||k||d.hasCSS||(d.hasCSS=!!c(a,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),l||i(a,d),a}var k,l,m="3.7.3-pre",n=a.html5||{},o=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,p=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,q="_html5shiv",r=0,s={};!function(){try{var a=b.createElement("a");a.innerHTML="",k="hidden"in a,l=1==a.childNodes.length||function(){b.createElement("a");var a=b.createDocumentFragment();return"undefined"==typeof a.cloneNode||"undefined"==typeof a.createDocumentFragment||"undefined"==typeof a.createElement}()}catch(c){k=!0,l=!0}}();var t={elements:n.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:m,shivCSS:n.shivCSS!==!1,supportsUnknownElements:l,shivMethods:n.shivMethods!==!1,type:"default",shivDocument:j,createElement:g,createDocumentFragment:h,addElements:e};a.html5=t,j(b),"object"==typeof module&&module.exports&&(module.exports=t)}("undefined"!=typeof window?window:this,document); \ No newline at end of file diff --git a/_static/js/theme.js b/_static/js/theme.js new file mode 100644 index 0000000..1fddb6e --- /dev/null +++ b/_static/js/theme.js @@ -0,0 +1 @@ +!function(n){var e={};function t(i){if(e[i])return e[i].exports;var o=e[i]={i:i,l:!1,exports:{}};return n[i].call(o.exports,o,o.exports,t),o.l=!0,o.exports}t.m=n,t.c=e,t.d=function(n,e,i){t.o(n,e)||Object.defineProperty(n,e,{enumerable:!0,get:i})},t.r=function(n){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(n,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(n,"__esModule",{value:!0})},t.t=function(n,e){if(1&e&&(n=t(n)),8&e)return n;if(4&e&&"object"==typeof n&&n&&n.__esModule)return n;var i=Object.create(null);if(t.r(i),Object.defineProperty(i,"default",{enumerable:!0,value:n}),2&e&&"string"!=typeof n)for(var o in n)t.d(i,o,function(e){return n[e]}.bind(null,o));return i},t.n=function(n){var e=n&&n.__esModule?function(){return n.default}:function(){return n};return t.d(e,"a",e),e},t.o=function(n,e){return Object.prototype.hasOwnProperty.call(n,e)},t.p="",t(t.s=0)}([function(n,e,t){t(1),n.exports=t(3)},function(n,e,t){(function(){var e="undefined"!=typeof window?window.jQuery:t(2);n.exports.ThemeNav={navBar:null,win:null,winScroll:!1,winResize:!1,linkScroll:!1,winPosition:0,winHeight:null,docHeight:null,isRunning:!1,enable:function(n){var t=this;void 0===n&&(n=!0),t.isRunning||(t.isRunning=!0,e((function(e){t.init(e),t.reset(),t.win.on("hashchange",t.reset),n&&t.win.on("scroll",(function(){t.linkScroll||t.winScroll||(t.winScroll=!0,requestAnimationFrame((function(){t.onScroll()})))})),t.win.on("resize",(function(){t.winResize||(t.winResize=!0,requestAnimationFrame((function(){t.onResize()})))})),t.onResize()})))},enableSticky:function(){this.enable(!0)},init:function(n){n(document);var e=this;this.navBar=n("div.wy-side-scroll:first"),this.win=n(window),n(document).on("click","[data-toggle='wy-nav-top']",(function(){n("[data-toggle='wy-nav-shift']").toggleClass("shift"),n("[data-toggle='rst-versions']").toggleClass("shift")})).on("click",".wy-menu-vertical .current ul li a",(function(){var t=n(this);n("[data-toggle='wy-nav-shift']").removeClass("shift"),n("[data-toggle='rst-versions']").toggleClass("shift"),e.toggleCurrent(t),e.hashChange()})).on("click","[data-toggle='rst-current-version']",(function(){n("[data-toggle='rst-versions']").toggleClass("shift-up")})),n("table.docutils:not(.field-list,.footnote,.citation)").wrap("
"),n("table.docutils.footnote").wrap("
"),n("table.docutils.citation").wrap("
"),n(".wy-menu-vertical ul").not(".simple").siblings("a").each((function(){var t=n(this);expand=n(''),expand.on("click",(function(n){return e.toggleCurrent(t),n.stopPropagation(),!1})),t.prepend(expand)}))},reset:function(){var n=encodeURI(window.location.hash)||"#";try{var e=$(".wy-menu-vertical"),t=e.find('[href="'+n+'"]');if(0===t.length){var i=$('.document [id="'+n.substring(1)+'"]').closest("div.section");0===(t=e.find('[href="#'+i.attr("id")+'"]')).length&&(t=e.find('[href="#"]'))}if(t.length>0){$(".wy-menu-vertical .current").removeClass("current").attr("aria-expanded","false"),t.addClass("current").attr("aria-expanded","true"),t.closest("li.toctree-l1").parent().addClass("current").attr("aria-expanded","true");for(let n=1;n<=10;n++)t.closest("li.toctree-l"+n).addClass("current").attr("aria-expanded","true");t[0].scrollIntoView()}}catch(n){console.log("Error expanding nav for anchor",n)}},onScroll:function(){this.winScroll=!1;var n=this.win.scrollTop(),e=n+this.winHeight,t=this.navBar.scrollTop()+(n-this.winPosition);n<0||e>this.docHeight||(this.navBar.scrollTop(t),this.winPosition=n)},onResize:function(){this.winResize=!1,this.winHeight=this.win.height(),this.docHeight=$(document).height()},hashChange:function(){this.linkScroll=!0,this.win.one("hashchange",(function(){this.linkScroll=!1}))},toggleCurrent:function(n){var e=n.closest("li");e.siblings("li.current").removeClass("current").attr("aria-expanded","false"),e.siblings().find("li.current").removeClass("current").attr("aria-expanded","false");var t=e.find("> ul li");t.length&&(t.removeClass("current").attr("aria-expanded","false"),e.toggleClass("current").attr("aria-expanded",(function(n,e){return"true"==e?"false":"true"})))}},"undefined"!=typeof window&&(window.SphinxRtdTheme={Navigation:n.exports.ThemeNav,StickyNav:n.exports.ThemeNav}),function(){for(var n=0,e=["ms","moz","webkit","o"],t=0;t0 + var meq1 = "^(" + C + ")?" + V + C + "(" + V + ")?$"; // [C]VC[V] is m=1 + var mgr1 = "^(" + C + ")?" + V + C + V + C; // [C]VCVC... is m>1 + var s_v = "^(" + C + ")?" + v; // vowel in stem + + this.stemWord = function (w) { + var stem; + var suffix; + var firstch; + var origword = w; + + if (w.length < 3) + return w; + + var re; + var re2; + var re3; + var re4; + + firstch = w.substr(0,1); + if (firstch == "y") + w = firstch.toUpperCase() + w.substr(1); + + // Step 1a + re = /^(.+?)(ss|i)es$/; + re2 = /^(.+?)([^s])s$/; + + if (re.test(w)) + w = w.replace(re,"$1$2"); + else if (re2.test(w)) + w = w.replace(re2,"$1$2"); + + // Step 1b + re = /^(.+?)eed$/; + re2 = /^(.+?)(ed|ing)$/; + if (re.test(w)) { + var fp = re.exec(w); + re = new RegExp(mgr0); + if (re.test(fp[1])) { + re = /.$/; + w = w.replace(re,""); + } + } + else if (re2.test(w)) { + var fp = re2.exec(w); + stem = fp[1]; + re2 = new RegExp(s_v); + if (re2.test(stem)) { + w = stem; + re2 = /(at|bl|iz)$/; + re3 = new RegExp("([^aeiouylsz])\\1$"); + re4 = new RegExp("^" + C + v + "[^aeiouwxy]$"); + if (re2.test(w)) + w = w + "e"; + else if (re3.test(w)) { + re = /.$/; + w = w.replace(re,""); + } + else if (re4.test(w)) + w = w + "e"; + } + } + + // Step 1c + re = /^(.+?)y$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(s_v); + if (re.test(stem)) + w = stem + "i"; + } + + // Step 2 + re = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + suffix = fp[2]; + re = new RegExp(mgr0); + if (re.test(stem)) + w = stem + step2list[suffix]; + } + + // Step 3 + re = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + suffix = fp[2]; + re = new RegExp(mgr0); + if (re.test(stem)) + w = stem + step3list[suffix]; + } + + // Step 4 + re = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/; + re2 = /^(.+?)(s|t)(ion)$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(mgr1); + if (re.test(stem)) + w = stem; + } + else if (re2.test(w)) { + var fp = re2.exec(w); + stem = fp[1] + fp[2]; + re2 = new RegExp(mgr1); + if (re2.test(stem)) + w = stem; + } + + // Step 5 + re = /^(.+?)e$/; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = new RegExp(mgr1); + re2 = new RegExp(meq1); + re3 = new RegExp("^" + C + v + "[^aeiouwxy]$"); + if (re.test(stem) || (re2.test(stem) && !(re3.test(stem)))) + w = stem; + } + re = /ll$/; + re2 = new RegExp(mgr1); + if (re.test(w) && re2.test(w)) { + re = /.$/; + w = w.replace(re,""); + } + + // and turn initial Y back to y + if (firstch == "y") + w = firstch.toLowerCase() + w.substr(1); + return w; + } +} + diff --git a/_static/minus.png b/_static/minus.png new file mode 100644 index 0000000..d96755f Binary files /dev/null and b/_static/minus.png differ diff --git a/_static/plus.png b/_static/plus.png new file mode 100644 index 0000000..7107cec Binary files /dev/null and b/_static/plus.png differ diff --git a/_static/pygments.css b/_static/pygments.css new file mode 100644 index 0000000..84ab303 --- /dev/null +++ b/_static/pygments.css @@ -0,0 +1,75 @@ +pre { line-height: 125%; } +td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } +span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } +td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +.highlight .hll { background-color: #ffffcc } +.highlight { background: #f8f8f8; } +.highlight .c { color: #3D7B7B; font-style: italic } /* Comment */ +.highlight .err { border: 1px solid #FF0000 } /* Error */ +.highlight .k { color: #008000; font-weight: bold } /* Keyword */ +.highlight .o { color: #666666 } /* Operator */ +.highlight .ch { color: #3D7B7B; font-style: italic } /* Comment.Hashbang */ +.highlight .cm { color: #3D7B7B; font-style: italic } /* Comment.Multiline */ +.highlight .cp { color: #9C6500 } /* Comment.Preproc */ +.highlight .cpf { color: #3D7B7B; font-style: italic } /* Comment.PreprocFile */ +.highlight .c1 { color: #3D7B7B; font-style: italic } /* Comment.Single */ +.highlight .cs { color: #3D7B7B; font-style: italic } /* Comment.Special */ +.highlight .gd { color: #A00000 } /* Generic.Deleted */ +.highlight .ge { font-style: italic } /* Generic.Emph */ +.highlight .ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */ +.highlight .gr { color: #E40000 } /* Generic.Error */ +.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */ +.highlight .gi { color: #008400 } /* Generic.Inserted */ +.highlight .go { color: #717171 } /* Generic.Output */ +.highlight .gp { color: #000080; font-weight: bold } /* Generic.Prompt */ +.highlight .gs { font-weight: bold } /* Generic.Strong */ +.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ +.highlight .gt { color: #0044DD } /* Generic.Traceback */ +.highlight .kc { color: #008000; font-weight: bold } /* Keyword.Constant */ +.highlight .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */ +.highlight .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */ +.highlight .kp { color: #008000 } /* Keyword.Pseudo */ +.highlight .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */ +.highlight .kt { color: #B00040 } /* Keyword.Type */ +.highlight .m { color: #666666 } /* Literal.Number */ +.highlight .s { color: #BA2121 } /* Literal.String */ +.highlight .na { color: #687822 } /* Name.Attribute */ +.highlight .nb { color: #008000 } /* Name.Builtin */ +.highlight .nc { color: #0000FF; font-weight: bold } /* Name.Class */ +.highlight .no { color: #880000 } /* Name.Constant */ +.highlight .nd { color: #AA22FF } /* Name.Decorator */ +.highlight .ni { color: #717171; font-weight: bold } /* Name.Entity */ +.highlight .ne { color: #CB3F38; font-weight: bold } /* Name.Exception */ +.highlight .nf { color: #0000FF } /* Name.Function */ +.highlight .nl { color: #767600 } /* Name.Label */ +.highlight .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */ +.highlight .nt { color: #008000; font-weight: bold } /* Name.Tag */ +.highlight .nv { color: #19177C } /* Name.Variable */ +.highlight .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */ +.highlight .w { color: #bbbbbb } /* Text.Whitespace */ +.highlight .mb { color: #666666 } /* Literal.Number.Bin */ +.highlight .mf { color: #666666 } /* Literal.Number.Float */ +.highlight .mh { color: #666666 } /* Literal.Number.Hex */ +.highlight .mi { color: #666666 } /* Literal.Number.Integer */ +.highlight .mo { color: #666666 } /* Literal.Number.Oct */ +.highlight .sa { color: #BA2121 } /* Literal.String.Affix */ +.highlight .sb { color: #BA2121 } /* Literal.String.Backtick */ +.highlight .sc { color: #BA2121 } /* Literal.String.Char */ +.highlight .dl { color: #BA2121 } /* Literal.String.Delimiter */ +.highlight .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */ +.highlight .s2 { color: #BA2121 } /* Literal.String.Double */ +.highlight .se { color: #AA5D1F; font-weight: bold } /* Literal.String.Escape */ +.highlight .sh { color: #BA2121 } /* Literal.String.Heredoc */ +.highlight .si { color: #A45A77; font-weight: bold } /* Literal.String.Interpol */ +.highlight .sx { color: #008000 } /* Literal.String.Other */ +.highlight .sr { color: #A45A77 } /* Literal.String.Regex */ +.highlight .s1 { color: #BA2121 } /* Literal.String.Single */ +.highlight .ss { color: #19177C } /* Literal.String.Symbol */ +.highlight .bp { color: #008000 } /* Name.Builtin.Pseudo */ +.highlight .fm { color: #0000FF } /* Name.Function.Magic */ +.highlight .vc { color: #19177C } /* Name.Variable.Class */ +.highlight .vg { color: #19177C } /* Name.Variable.Global */ +.highlight .vi { color: #19177C } /* Name.Variable.Instance */ +.highlight .vm { color: #19177C } /* Name.Variable.Magic */ +.highlight .il { color: #666666 } /* Literal.Number.Integer.Long */ \ No newline at end of file diff --git a/_static/searchtools.js b/_static/searchtools.js new file mode 100644 index 0000000..92da3f8 --- /dev/null +++ b/_static/searchtools.js @@ -0,0 +1,619 @@ +/* + * searchtools.js + * ~~~~~~~~~~~~~~~~ + * + * Sphinx JavaScript utilities for the full-text search. + * + * :copyright: Copyright 2007-2024 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ +"use strict"; + +/** + * Simple result scoring code. + */ +if (typeof Scorer === "undefined") { + var Scorer = { + // Implement the following function to further tweak the score for each result + // The function takes a result array [docname, title, anchor, descr, score, filename] + // and returns the new score. + /* + score: result => { + const [docname, title, anchor, descr, score, filename] = result + return score + }, + */ + + // query matches the full name of an object + objNameMatch: 11, + // or matches in the last dotted part of the object name + objPartialMatch: 6, + // Additive scores depending on the priority of the object + objPrio: { + 0: 15, // used to be importantResults + 1: 5, // used to be objectResults + 2: -5, // used to be unimportantResults + }, + // Used when the priority is not in the mapping. + objPrioDefault: 0, + + // query found in title + title: 15, + partialTitle: 7, + // query found in terms + term: 5, + partialTerm: 2, + }; +} + +const _removeChildren = (element) => { + while (element && element.lastChild) element.removeChild(element.lastChild); +}; + +/** + * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#escaping + */ +const _escapeRegExp = (string) => + string.replace(/[.*+\-?^${}()|[\]\\]/g, "\\$&"); // $& means the whole matched string + +const _displayItem = (item, searchTerms, highlightTerms) => { + const docBuilder = DOCUMENTATION_OPTIONS.BUILDER; + const docFileSuffix = DOCUMENTATION_OPTIONS.FILE_SUFFIX; + const docLinkSuffix = DOCUMENTATION_OPTIONS.LINK_SUFFIX; + const showSearchSummary = DOCUMENTATION_OPTIONS.SHOW_SEARCH_SUMMARY; + const contentRoot = document.documentElement.dataset.content_root; + + const [docName, title, anchor, descr, score, _filename] = item; + + let listItem = document.createElement("li"); + let requestUrl; + let linkUrl; + if (docBuilder === "dirhtml") { + // dirhtml builder + let dirname = docName + "/"; + if (dirname.match(/\/index\/$/)) + dirname = dirname.substring(0, dirname.length - 6); + else if (dirname === "index/") dirname = ""; + requestUrl = contentRoot + dirname; + linkUrl = requestUrl; + } else { + // normal html builders + requestUrl = contentRoot + docName + docFileSuffix; + linkUrl = docName + docLinkSuffix; + } + let linkEl = listItem.appendChild(document.createElement("a")); + linkEl.href = linkUrl + anchor; + linkEl.dataset.score = score; + linkEl.innerHTML = title; + if (descr) { + listItem.appendChild(document.createElement("span")).innerHTML = + " (" + descr + ")"; + // highlight search terms in the description + if (SPHINX_HIGHLIGHT_ENABLED) // set in sphinx_highlight.js + highlightTerms.forEach((term) => _highlightText(listItem, term, "highlighted")); + } + else if (showSearchSummary) + fetch(requestUrl) + .then((responseData) => responseData.text()) + .then((data) => { + if (data) + listItem.appendChild( + Search.makeSearchSummary(data, searchTerms, anchor) + ); + // highlight search terms in the summary + if (SPHINX_HIGHLIGHT_ENABLED) // set in sphinx_highlight.js + highlightTerms.forEach((term) => _highlightText(listItem, term, "highlighted")); + }); + Search.output.appendChild(listItem); +}; +const _finishSearch = (resultCount) => { + Search.stopPulse(); + Search.title.innerText = _("Search Results"); + if (!resultCount) + Search.status.innerText = Documentation.gettext( + "Your search did not match any documents. Please make sure that all words are spelled correctly and that you've selected enough categories." + ); + else + Search.status.innerText = _( + "Search finished, found ${resultCount} page(s) matching the search query." + ).replace('${resultCount}', resultCount); +}; +const _displayNextItem = ( + results, + resultCount, + searchTerms, + highlightTerms, +) => { + // results left, load the summary and display it + // this is intended to be dynamic (don't sub resultsCount) + if (results.length) { + _displayItem(results.pop(), searchTerms, highlightTerms); + setTimeout( + () => _displayNextItem(results, resultCount, searchTerms, highlightTerms), + 5 + ); + } + // search finished, update title and status message + else _finishSearch(resultCount); +}; +// Helper function used by query() to order search results. +// Each input is an array of [docname, title, anchor, descr, score, filename]. +// Order the results by score (in opposite order of appearance, since the +// `_displayNextItem` function uses pop() to retrieve items) and then alphabetically. +const _orderResultsByScoreThenName = (a, b) => { + const leftScore = a[4]; + const rightScore = b[4]; + if (leftScore === rightScore) { + // same score: sort alphabetically + const leftTitle = a[1].toLowerCase(); + const rightTitle = b[1].toLowerCase(); + if (leftTitle === rightTitle) return 0; + return leftTitle > rightTitle ? -1 : 1; // inverted is intentional + } + return leftScore > rightScore ? 1 : -1; +}; + +/** + * Default splitQuery function. Can be overridden in ``sphinx.search`` with a + * custom function per language. + * + * The regular expression works by splitting the string on consecutive characters + * that are not Unicode letters, numbers, underscores, or emoji characters. + * This is the same as ``\W+`` in Python, preserving the surrogate pair area. + */ +if (typeof splitQuery === "undefined") { + var splitQuery = (query) => query + .split(/[^\p{Letter}\p{Number}_\p{Emoji_Presentation}]+/gu) + .filter(term => term) // remove remaining empty strings +} + +/** + * Search Module + */ +const Search = { + _index: null, + _queued_query: null, + _pulse_status: -1, + + htmlToText: (htmlString, anchor) => { + const htmlElement = new DOMParser().parseFromString(htmlString, 'text/html'); + for (const removalQuery of [".headerlinks", "script", "style"]) { + htmlElement.querySelectorAll(removalQuery).forEach((el) => { el.remove() }); + } + if (anchor) { + const anchorContent = htmlElement.querySelector(`[role="main"] ${anchor}`); + if (anchorContent) return anchorContent.textContent; + + console.warn( + `Anchored content block not found. Sphinx search tries to obtain it via DOM query '[role=main] ${anchor}'. Check your theme or template.` + ); + } + + // if anchor not specified or not found, fall back to main content + const docContent = htmlElement.querySelector('[role="main"]'); + if (docContent) return docContent.textContent; + + console.warn( + "Content block not found. Sphinx search tries to obtain it via DOM query '[role=main]'. Check your theme or template." + ); + return ""; + }, + + init: () => { + const query = new URLSearchParams(window.location.search).get("q"); + document + .querySelectorAll('input[name="q"]') + .forEach((el) => (el.value = query)); + if (query) Search.performSearch(query); + }, + + loadIndex: (url) => + (document.body.appendChild(document.createElement("script")).src = url), + + setIndex: (index) => { + Search._index = index; + if (Search._queued_query !== null) { + const query = Search._queued_query; + Search._queued_query = null; + Search.query(query); + } + }, + + hasIndex: () => Search._index !== null, + + deferQuery: (query) => (Search._queued_query = query), + + stopPulse: () => (Search._pulse_status = -1), + + startPulse: () => { + if (Search._pulse_status >= 0) return; + + const pulse = () => { + Search._pulse_status = (Search._pulse_status + 1) % 4; + Search.dots.innerText = ".".repeat(Search._pulse_status); + if (Search._pulse_status >= 0) window.setTimeout(pulse, 500); + }; + pulse(); + }, + + /** + * perform a search for something (or wait until index is loaded) + */ + performSearch: (query) => { + // create the required interface elements + const searchText = document.createElement("h2"); + searchText.textContent = _("Searching"); + const searchSummary = document.createElement("p"); + searchSummary.classList.add("search-summary"); + searchSummary.innerText = ""; + const searchList = document.createElement("ul"); + searchList.classList.add("search"); + + const out = document.getElementById("search-results"); + Search.title = out.appendChild(searchText); + Search.dots = Search.title.appendChild(document.createElement("span")); + Search.status = out.appendChild(searchSummary); + Search.output = out.appendChild(searchList); + + const searchProgress = document.getElementById("search-progress"); + // Some themes don't use the search progress node + if (searchProgress) { + searchProgress.innerText = _("Preparing search..."); + } + Search.startPulse(); + + // index already loaded, the browser was quick! + if (Search.hasIndex()) Search.query(query); + else Search.deferQuery(query); + }, + + _parseQuery: (query) => { + // stem the search terms and add them to the correct list + const stemmer = new Stemmer(); + const searchTerms = new Set(); + const excludedTerms = new Set(); + const highlightTerms = new Set(); + const objectTerms = new Set(splitQuery(query.toLowerCase().trim())); + splitQuery(query.trim()).forEach((queryTerm) => { + const queryTermLower = queryTerm.toLowerCase(); + + // maybe skip this "word" + // stopwords array is from language_data.js + if ( + stopwords.indexOf(queryTermLower) !== -1 || + queryTerm.match(/^\d+$/) + ) + return; + + // stem the word + let word = stemmer.stemWord(queryTermLower); + // select the correct list + if (word[0] === "-") excludedTerms.add(word.substr(1)); + else { + searchTerms.add(word); + highlightTerms.add(queryTermLower); + } + }); + + if (SPHINX_HIGHLIGHT_ENABLED) { // set in sphinx_highlight.js + localStorage.setItem("sphinx_highlight_terms", [...highlightTerms].join(" ")) + } + + // console.debug("SEARCH: searching for:"); + // console.info("required: ", [...searchTerms]); + // console.info("excluded: ", [...excludedTerms]); + + return [query, searchTerms, excludedTerms, highlightTerms, objectTerms]; + }, + + /** + * execute search (requires search index to be loaded) + */ + _performSearch: (query, searchTerms, excludedTerms, highlightTerms, objectTerms) => { + const filenames = Search._index.filenames; + const docNames = Search._index.docnames; + const titles = Search._index.titles; + const allTitles = Search._index.alltitles; + const indexEntries = Search._index.indexentries; + + // Collect multiple result groups to be sorted separately and then ordered. + // Each is an array of [docname, title, anchor, descr, score, filename]. + const normalResults = []; + const nonMainIndexResults = []; + + _removeChildren(document.getElementById("search-progress")); + + const queryLower = query.toLowerCase().trim(); + for (const [title, foundTitles] of Object.entries(allTitles)) { + if (title.toLowerCase().trim().includes(queryLower) && (queryLower.length >= title.length/2)) { + for (const [file, id] of foundTitles) { + let score = Math.round(100 * queryLower.length / title.length) + normalResults.push([ + docNames[file], + titles[file] !== title ? `${titles[file]} > ${title}` : title, + id !== null ? "#" + id : "", + null, + score, + filenames[file], + ]); + } + } + } + + // search for explicit entries in index directives + for (const [entry, foundEntries] of Object.entries(indexEntries)) { + if (entry.includes(queryLower) && (queryLower.length >= entry.length/2)) { + for (const [file, id, isMain] of foundEntries) { + const score = Math.round(100 * queryLower.length / entry.length); + const result = [ + docNames[file], + titles[file], + id ? "#" + id : "", + null, + score, + filenames[file], + ]; + if (isMain) { + normalResults.push(result); + } else { + nonMainIndexResults.push(result); + } + } + } + } + + // lookup as object + objectTerms.forEach((term) => + normalResults.push(...Search.performObjectSearch(term, objectTerms)) + ); + + // lookup as search terms in fulltext + normalResults.push(...Search.performTermsSearch(searchTerms, excludedTerms)); + + // let the scorer override scores with a custom scoring function + if (Scorer.score) { + normalResults.forEach((item) => (item[4] = Scorer.score(item))); + nonMainIndexResults.forEach((item) => (item[4] = Scorer.score(item))); + } + + // Sort each group of results by score and then alphabetically by name. + normalResults.sort(_orderResultsByScoreThenName); + nonMainIndexResults.sort(_orderResultsByScoreThenName); + + // Combine the result groups in (reverse) order. + // Non-main index entries are typically arbitrary cross-references, + // so display them after other results. + let results = [...nonMainIndexResults, ...normalResults]; + + // remove duplicate search results + // note the reversing of results, so that in the case of duplicates, the highest-scoring entry is kept + let seen = new Set(); + results = results.reverse().reduce((acc, result) => { + let resultStr = result.slice(0, 4).concat([result[5]]).map(v => String(v)).join(','); + if (!seen.has(resultStr)) { + acc.push(result); + seen.add(resultStr); + } + return acc; + }, []); + + return results.reverse(); + }, + + query: (query) => { + const [searchQuery, searchTerms, excludedTerms, highlightTerms, objectTerms] = Search._parseQuery(query); + const results = Search._performSearch(searchQuery, searchTerms, excludedTerms, highlightTerms, objectTerms); + + // for debugging + //Search.lastresults = results.slice(); // a copy + // console.info("search results:", Search.lastresults); + + // print the results + _displayNextItem(results, results.length, searchTerms, highlightTerms); + }, + + /** + * search for object names + */ + performObjectSearch: (object, objectTerms) => { + const filenames = Search._index.filenames; + const docNames = Search._index.docnames; + const objects = Search._index.objects; + const objNames = Search._index.objnames; + const titles = Search._index.titles; + + const results = []; + + const objectSearchCallback = (prefix, match) => { + const name = match[4] + const fullname = (prefix ? prefix + "." : "") + name; + const fullnameLower = fullname.toLowerCase(); + if (fullnameLower.indexOf(object) < 0) return; + + let score = 0; + const parts = fullnameLower.split("."); + + // check for different match types: exact matches of full name or + // "last name" (i.e. last dotted part) + if (fullnameLower === object || parts.slice(-1)[0] === object) + score += Scorer.objNameMatch; + else if (parts.slice(-1)[0].indexOf(object) > -1) + score += Scorer.objPartialMatch; // matches in last name + + const objName = objNames[match[1]][2]; + const title = titles[match[0]]; + + // If more than one term searched for, we require other words to be + // found in the name/title/description + const otherTerms = new Set(objectTerms); + otherTerms.delete(object); + if (otherTerms.size > 0) { + const haystack = `${prefix} ${name} ${objName} ${title}`.toLowerCase(); + if ( + [...otherTerms].some((otherTerm) => haystack.indexOf(otherTerm) < 0) + ) + return; + } + + let anchor = match[3]; + if (anchor === "") anchor = fullname; + else if (anchor === "-") anchor = objNames[match[1]][1] + "-" + fullname; + + const descr = objName + _(", in ") + title; + + // add custom score for some objects according to scorer + if (Scorer.objPrio.hasOwnProperty(match[2])) + score += Scorer.objPrio[match[2]]; + else score += Scorer.objPrioDefault; + + results.push([ + docNames[match[0]], + fullname, + "#" + anchor, + descr, + score, + filenames[match[0]], + ]); + }; + Object.keys(objects).forEach((prefix) => + objects[prefix].forEach((array) => + objectSearchCallback(prefix, array) + ) + ); + return results; + }, + + /** + * search for full-text terms in the index + */ + performTermsSearch: (searchTerms, excludedTerms) => { + // prepare search + const terms = Search._index.terms; + const titleTerms = Search._index.titleterms; + const filenames = Search._index.filenames; + const docNames = Search._index.docnames; + const titles = Search._index.titles; + + const scoreMap = new Map(); + const fileMap = new Map(); + + // perform the search on the required terms + searchTerms.forEach((word) => { + const files = []; + const arr = [ + { files: terms[word], score: Scorer.term }, + { files: titleTerms[word], score: Scorer.title }, + ]; + // add support for partial matches + if (word.length > 2) { + const escapedWord = _escapeRegExp(word); + if (!terms.hasOwnProperty(word)) { + Object.keys(terms).forEach((term) => { + if (term.match(escapedWord)) + arr.push({ files: terms[term], score: Scorer.partialTerm }); + }); + } + if (!titleTerms.hasOwnProperty(word)) { + Object.keys(titleTerms).forEach((term) => { + if (term.match(escapedWord)) + arr.push({ files: titleTerms[term], score: Scorer.partialTitle }); + }); + } + } + + // no match but word was a required one + if (arr.every((record) => record.files === undefined)) return; + + // found search word in contents + arr.forEach((record) => { + if (record.files === undefined) return; + + let recordFiles = record.files; + if (recordFiles.length === undefined) recordFiles = [recordFiles]; + files.push(...recordFiles); + + // set score for the word in each file + recordFiles.forEach((file) => { + if (!scoreMap.has(file)) scoreMap.set(file, {}); + scoreMap.get(file)[word] = record.score; + }); + }); + + // create the mapping + files.forEach((file) => { + if (!fileMap.has(file)) fileMap.set(file, [word]); + else if (fileMap.get(file).indexOf(word) === -1) fileMap.get(file).push(word); + }); + }); + + // now check if the files don't contain excluded terms + const results = []; + for (const [file, wordList] of fileMap) { + // check if all requirements are matched + + // as search terms with length < 3 are discarded + const filteredTermCount = [...searchTerms].filter( + (term) => term.length > 2 + ).length; + if ( + wordList.length !== searchTerms.size && + wordList.length !== filteredTermCount + ) + continue; + + // ensure that none of the excluded terms is in the search result + if ( + [...excludedTerms].some( + (term) => + terms[term] === file || + titleTerms[term] === file || + (terms[term] || []).includes(file) || + (titleTerms[term] || []).includes(file) + ) + ) + break; + + // select one (max) score for the file. + const score = Math.max(...wordList.map((w) => scoreMap.get(file)[w])); + // add result to the result list + results.push([ + docNames[file], + titles[file], + "", + null, + score, + filenames[file], + ]); + } + return results; + }, + + /** + * helper function to return a node containing the + * search summary for a given text. keywords is a list + * of stemmed words. + */ + makeSearchSummary: (htmlText, keywords, anchor) => { + const text = Search.htmlToText(htmlText, anchor); + if (text === "") return null; + + const textLower = text.toLowerCase(); + const actualStartPosition = [...keywords] + .map((k) => textLower.indexOf(k.toLowerCase())) + .filter((i) => i > -1) + .slice(-1)[0]; + const startWithContext = Math.max(actualStartPosition - 120, 0); + + const top = startWithContext === 0 ? "" : "..."; + const tail = startWithContext + 240 < text.length ? "..." : ""; + + let summary = document.createElement("p"); + summary.classList.add("context"); + summary.textContent = top + text.substr(startWithContext, 240).trim() + tail; + + return summary; + }, +}; + +_ready(Search.init); diff --git a/_static/sphinx_highlight.js b/_static/sphinx_highlight.js new file mode 100644 index 0000000..8a96c69 --- /dev/null +++ b/_static/sphinx_highlight.js @@ -0,0 +1,154 @@ +/* Highlighting utilities for Sphinx HTML documentation. */ +"use strict"; + +const SPHINX_HIGHLIGHT_ENABLED = true + +/** + * highlight a given string on a node by wrapping it in + * span elements with the given class name. + */ +const _highlight = (node, addItems, text, className) => { + if (node.nodeType === Node.TEXT_NODE) { + const val = node.nodeValue; + const parent = node.parentNode; + const pos = val.toLowerCase().indexOf(text); + if ( + pos >= 0 && + !parent.classList.contains(className) && + !parent.classList.contains("nohighlight") + ) { + let span; + + const closestNode = parent.closest("body, svg, foreignObject"); + const isInSVG = closestNode && closestNode.matches("svg"); + if (isInSVG) { + span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); + } else { + span = document.createElement("span"); + span.classList.add(className); + } + + span.appendChild(document.createTextNode(val.substr(pos, text.length))); + const rest = document.createTextNode(val.substr(pos + text.length)); + parent.insertBefore( + span, + parent.insertBefore( + rest, + node.nextSibling + ) + ); + node.nodeValue = val.substr(0, pos); + /* There may be more occurrences of search term in this node. So call this + * function recursively on the remaining fragment. + */ + _highlight(rest, addItems, text, className); + + if (isInSVG) { + const rect = document.createElementNS( + "http://www.w3.org/2000/svg", + "rect" + ); + const bbox = parent.getBBox(); + rect.x.baseVal.value = bbox.x; + rect.y.baseVal.value = bbox.y; + rect.width.baseVal.value = bbox.width; + rect.height.baseVal.value = bbox.height; + rect.setAttribute("class", className); + addItems.push({ parent: parent, target: rect }); + } + } + } else if (node.matches && !node.matches("button, select, textarea")) { + node.childNodes.forEach((el) => _highlight(el, addItems, text, className)); + } +}; +const _highlightText = (thisNode, text, className) => { + let addItems = []; + _highlight(thisNode, addItems, text, className); + addItems.forEach((obj) => + obj.parent.insertAdjacentElement("beforebegin", obj.target) + ); +}; + +/** + * Small JavaScript module for the documentation. + */ +const SphinxHighlight = { + + /** + * highlight the search words provided in localstorage in the text + */ + highlightSearchWords: () => { + if (!SPHINX_HIGHLIGHT_ENABLED) return; // bail if no highlight + + // get and clear terms from localstorage + const url = new URL(window.location); + const highlight = + localStorage.getItem("sphinx_highlight_terms") + || url.searchParams.get("highlight") + || ""; + localStorage.removeItem("sphinx_highlight_terms") + url.searchParams.delete("highlight"); + window.history.replaceState({}, "", url); + + // get individual terms from highlight string + const terms = highlight.toLowerCase().split(/\s+/).filter(x => x); + if (terms.length === 0) return; // nothing to do + + // There should never be more than one element matching "div.body" + const divBody = document.querySelectorAll("div.body"); + const body = divBody.length ? divBody[0] : document.querySelector("body"); + window.setTimeout(() => { + terms.forEach((term) => _highlightText(body, term, "highlighted")); + }, 10); + + const searchBox = document.getElementById("searchbox"); + if (searchBox === null) return; + searchBox.appendChild( + document + .createRange() + .createContextualFragment( + '" + ) + ); + }, + + /** + * helper function to hide the search marks again + */ + hideSearchWords: () => { + document + .querySelectorAll("#searchbox .highlight-link") + .forEach((el) => el.remove()); + document + .querySelectorAll("span.highlighted") + .forEach((el) => el.classList.remove("highlighted")); + localStorage.removeItem("sphinx_highlight_terms") + }, + + initEscapeListener: () => { + // only install a listener if it is really needed + if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) return; + + document.addEventListener("keydown", (event) => { + // bail for input elements + if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return; + // bail with special keys + if (event.shiftKey || event.altKey || event.ctrlKey || event.metaKey) return; + if (DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS && (event.key === "Escape")) { + SphinxHighlight.hideSearchWords(); + event.preventDefault(); + } + }); + }, +}; + +_ready(() => { + /* Do not call highlightSearchWords() when we are on the search page. + * It will highlight words from the *previous* search query. + */ + if (typeof Search === "undefined") SphinxHighlight.highlightSearchWords(); + SphinxHighlight.initEscapeListener(); +}); diff --git a/genindex.html b/genindex.html new file mode 100644 index 0000000..d341474 --- /dev/null +++ b/genindex.html @@ -0,0 +1,827 @@ + + + + + + Index — fastvpinns 1.0.0 documentation + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + +
  • +
  • +
+
+
+
+
+ + +

Index

+ +
+ A + | B + | C + | D + | F + | G + | J + | M + | P + | Q + | R + | S + | T + | V + | W + +
+

A

+ + + +
+ +

B

+ + +
+ +

C

+ + + +
+ +

D

+ + + +
+ +

F

+ + + +
    +
  • + fastvpinns.data.datahandler + +
  • +
  • + fastvpinns.data.datahandler2d + +
  • +
  • + fastvpinns.FE.basis_2d_QN_Jacobi + +
  • +
  • + fastvpinns.FE.FE2D_Cell + +
  • +
  • + fastvpinns.FE.fe2d_setup_main + +
  • +
  • + fastvpinns.FE.fe_transformation_2d + +
  • +
  • + fastvpinns.FE.fespace + +
  • +
  • + fastvpinns.FE.fespace2d + +
  • +
  • + fastvpinns.FE.quad_affine + +
  • +
  • + fastvpinns.FE.quad_bilinear + +
  • +
  • + fastvpinns.FE.quadratureformulas + +
  • +
  • + fastvpinns.FE.quadratureformulas_quad2d + +
  • +
  • + fastvpinns.Geometry.geometry + +
  • +
  • + fastvpinns.Geometry.geometry_2d + +
  • +
  • + fastvpinns.model.model + +
  • +
+ +

G

+ + + +
+ +

J

+ + +
+ +

M

+ + +
+ +

P

+ + + +
+ +

Q

+ + + +
+ +

R

+ + +
+ +

S

+ + + +
+ +

T

+ + +
+ +

V

+ + +
+ +

W

+ + +
+ + + +
+
+
+ +
+ +
+

© Copyright 2024, Thivin Anandh, Divij Ghose, Sashikumaar Ganesan.

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 0000000..29084ae --- /dev/null +++ b/index.html @@ -0,0 +1,206 @@ + + + + + + + Welcome to FastVPINNs’s documentation! — fastvpinns 1.0.0 documentation + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Welcome to FastVPINNs’s documentation!

+Unit tests +Integration tests +Compatibility check +Code coverage +MIT License +Code style: black +Python Versions +

A robust tensor-based deep learning framework for solving PDE’s using hp-Variational Physics-Informed Neural Networks (hp-VPINNs). The framework supports handling complex geometries and uses tensor-based loss computation to accelerate the training of conventional hp-VPINNs. +The framework is based on the work by FastVPINNs Paper. The framework is written on Tensorflow 2.0 and has support for handling external meshes.

+

Note: This framework is a highly optimised version of the the initial implementation of hp-VPINNs by kharazmi. Ref hp-VPINNs(arXiv).

+
+

Variational Physics-informed neural network

+

Variational Physics-Informed neural networks are special form of physics informed neural networks, which uses variational form of the loss function to train the NN. A special form of hp-Variational PINNs which uses h- & p- refinement to enhance the ability of the NN to capture higher frequency solutions. +For more details on the theory and implementation of hp-VPINNs, please refer to the FastVPINNs Paper and hp-VPINNs Paper.

+VPINNs Image + + +
+

API Reference

+ +
+ +
+
+
+

Indices and tables

+ +
+ + +
+
+
+ +
+ +
+

© Copyright 2024, Thivin Anandh, Divij Ghose, Sashikumaar Ganesan.

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/objects.inv b/objects.inv new file mode 100644 index 0000000..9ad391b Binary files /dev/null and b/objects.inv differ diff --git a/py-modindex.html b/py-modindex.html new file mode 100644 index 0000000..c3eb2bc --- /dev/null +++ b/py-modindex.html @@ -0,0 +1,276 @@ + + + + + + Python Module Index — fastvpinns 1.0.0 documentation + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + +
  • +
  • +
+
+
+
+
+ + +

Python Module Index

+ +
+ f +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
 
+ f
+ fastvpinns +
    + fastvpinns.data.datahandler +
    + fastvpinns.data.datahandler2d +
    + fastvpinns.FE.basis_2d_QN_Jacobi +
    + fastvpinns.FE.FE2D_Cell +
    + fastvpinns.FE.fe2d_setup_main +
    + fastvpinns.FE.fe_transformation_2d +
    + fastvpinns.FE.fespace +
    + fastvpinns.FE.fespace2d +
    + fastvpinns.FE.quad_affine +
    + fastvpinns.FE.quad_bilinear +
    + fastvpinns.FE.quadratureformulas +
    + fastvpinns.FE.quadratureformulas_quad2d +
    + fastvpinns.Geometry.geometry +
    + fastvpinns.Geometry.geometry_2d +
    + fastvpinns.model.model +
    + fastvpinns.model.model_hard +
    + fastvpinns.model.model_inverse +
    + fastvpinns.model.model_inverse_domain +
    + fastvpinns.physics.cd2d +
    + fastvpinns.physics.cd2d_inverse +
    + fastvpinns.physics.cd2d_inverse_domain +
    + fastvpinns.physics.helmholtz2d +
    + fastvpinns.physics.poisson2d +
    + fastvpinns.physics.poisson2d_inverse +
    + fastvpinns.utils.compute_utils +
    + fastvpinns.utils.plot_utils +
    + fastvpinns.utils.print_utils +
+ + +
+
+
+ +
+ +
+

© Copyright 2024, Thivin Anandh, Divij Ghose, Sashikumaar Ganesan.

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/search.html b/search.html new file mode 100644 index 0000000..2aab56d --- /dev/null +++ b/search.html @@ -0,0 +1,141 @@ + + + + + + Search — fastvpinns 1.0.0 documentation + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + +
  • +
  • +
+
+
+
+
+ + + + +
+ +
+ +
+
+
+ +
+ +
+

© Copyright 2024, Thivin Anandh, Divij Ghose, Sashikumaar Ganesan.

+
+ + Built with Sphinx using a + theme + provided by Read the Docs. + + +
+
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/searchindex.js b/searchindex.js new file mode 100644 index 0000000..e04bc2b --- /dev/null +++ b/searchindex.js @@ -0,0 +1 @@ +Search.setIndex({"alltitles": {"API Reference": [[45, null]], "Cite FastVPINNs": [[0, "cite-fastvpinns"]], "Community": [[45, null]], "Computational Domain": [[36, "computational-domain"], [37, "computational-domain"], [38, "computational-domain"], [39, "computational-domain"], [44, "computational-domain"]], "Contents": [[36, "contents"], [37, "contents"], [38, "contents"], [39, "contents"], [40, "contents"], [41, "contents"], [42, "contents"], [43, "contents"], [44, "contents"]], "Convection Diffusion 2D Example on Circular Domain": [[36, "convection-diffusion-2d-example-on-circular-domain"]], "Convection-Diffusion 2D Example on Circular Domain": [[37, "convection-diffusion-2d-example-on-circular-domain"]], "Data": [[6, "data"]], "Defining bilinear parameters": [[40, "defining-bilinear-parameters"], [41, "defining-bilinear-parameters"], [42, "defining-bilinear-parameters"], [43, "defining-bilinear-parameters"], [44, "defining-bilinear-parameters"]], "Defining boundary": [[40, "defining-boundary"]], "Defining boundary conditions": [[43, "defining-boundary-conditions"], [44, "defining-boundary-conditions"]], "Defining boundary values": [[41, "defining-boundary-values"], [42, "defining-boundary-values"], [44, "defining-boundary-values"]], "Defining the bilinear form": [[36, "defining-the-bilinear-form"], [37, "defining-the-bilinear-form"], [38, "defining-the-bilinear-form"], [39, "defining-the-bilinear-form"]], "Defining the boundary conditions": [[36, "defining-the-boundary-conditions"], [37, "defining-the-boundary-conditions"], [38, "defining-the-boundary-conditions"], [39, "defining-the-boundary-conditions"]], "Defining the exact solution": [[36, "defining-the-exact-solution"], [37, "defining-the-exact-solution"], [38, "defining-the-exact-solution"], [39, "defining-the-exact-solution"]], "Defining the forcing function": [[40, "defining-the-forcing-function"], [41, "defining-the-forcing-function"], [42, "defining-the-forcing-function"], [43, "defining-the-forcing-function"], [44, "defining-the-forcing-function"]], "Defining the hard boundary constraint ansatz": [[40, "defining-the-hard-boundary-constraint-ansatz"]], "Defining the source term": [[36, "defining-the-source-term"], [37, "defining-the-source-term"], [38, "defining-the-source-term"], [39, "defining-the-source-term"]], "Defining the target parameter values for testing": [[43, "defining-the-target-parameter-values-for-testing"], [44, "defining-the-target-parameter-values-for-testing"]], "Example File": [[40, "example-file"], [41, "example-file"], [42, "example-file"], [43, "example-file"], [44, "example-file"]], "Example File - cd2d_example.py": [[36, "example-file-cd2d-example-py"]], "Example File - cd2d_gear_example.py": [[37, "example-file-cd2d-gear-example-py"]], "Example File - helmholtz_example.py": [[38, "example-file-helmholtz-example-py"]], "Example File - sin_cos.py": [[39, "example-file-sin-cos-py"]], "Example-Problems": [[45, null]], "Experimentation": [[36, "experimentation"], [37, "experimentation"], [38, "experimentation"], [39, "experimentation"]], "FE": [[6, "fe"]], "FastVPINNs Module Documentation": [[6, "fastvpinns-module-documentation"]], "FastVPINNs Team": [[4, "fastvpinns-team"]], "FastVPINNs Tutorials": [[5, "fastvpinns-tutorials"]], "Finite Element Setup": [[6, "finite-element-setup"]], "Finite Element Space": [[36, "finite-element-space"], [37, "finite-element-space"], [38, "finite-element-space"], [39, "finite-element-space"]], "Finite Element Test Functions": [[6, "finite-element-test-functions"]], "Finite Element Transformations": [[6, "finite-element-transformations"]], "Forward Problems": [[5, "forward-problems"], [6, "forward-problems"]], "Geometry": [[6, "geometry"], [36, "geometry"], [37, "geometry"], [38, "geometry"], [39, "geometry"]], "Getting Started": [[45, null]], "Helmholtz 2D Example on Circular Domain": [[38, "helmholtz-2d-example-on-circular-domain"]], "How to Contribute": [[1, "how-to-contribute"]], "Import relevant FastVPINNs methods": [[40, "import-relevant-fastvpinns-methods"], [41, "import-relevant-fastvpinns-methods"], [42, "import-relevant-fastvpinns-methods"], [43, "import-relevant-fastvpinns-methods"], [44, "import-relevant-fastvpinns-methods"]], "Importing the required libraries": [[36, "importing-the-required-libraries"], [37, "importing-the-required-libraries"], [38, "importing-the-required-libraries"], [39, "importing-the-required-libraries"]], "Indices and tables": [[45, "indices-and-tables"]], "Input File": [[36, "input-file"], [37, "input-file"], [38, "input-file"], [39, "input-file"]], "Input file": [[40, "input-file"], [41, "input-file"], [42, "input-file"], [43, "input-file"], [44, "input-file"]], "Installation": [[2, "installation"]], "Installing from source": [[2, "installing-from-source"]], "Installing via PIP": [[2, "installing-via-pip"]], "Instantiating a model": [[41, "instantiating-a-model"], [42, "instantiating-a-model"]], "Instantiating a model with hard boundary constraints": [[40, "instantiating-a-model-with-hard-boundary-constraints"]], "Instantiating an inverse problem model": [[43, "instantiating-an-inverse-problem-model"]], "Inverse Problems": [[5, "inverse-problems"]], "Inverse Problems (Constant Coefficient)": [[6, "inverse-problems-constant-coefficient"]], "Inverse Problems (Spatially Varying Coefficient)": [[6, "inverse-problems-spatially-varying-coefficient"]], "License": [[3, "license"]], "Main File - main_cd2d.py": [[36, "main-file-main-cd2d-py"], [37, "main-file-main-cd2d-py"]], "Main File - main_helmholtz.py": [[38, "main-file-main-helmholtz-py"]], "Main File - main_poisson2d.py": [[39, "main-file-main-poisson2d-py"]], "Main file": [[40, "main-file"], [41, "main-file"], [42, "main-file"], [43, "main-file"], [44, "main-file"]], "Model": [[6, "model"]], "Model Types": [[6, "model-types"]], "Physics": [[6, "physics"]], "Poisson 2D Example on Circular Domain": [[39, "poisson-2d-example-on-circular-domain"]], "Post Training": [[36, "post-training"], [37, "post-training"], [38, "post-training"], [39, "post-training"]], "Pre-train setup": [[36, "pre-train-setup"], [37, "pre-train-setup"], [38, "pre-train-setup"], [39, "pre-train-setup"]], "Problems on Complex geometry": [[5, "problems-on-complex-geometry"]], "Problems on Uniform Mesh": [[5, "problems-on-uniform-mesh"]], "Problems with Hard boundary constraints": [[5, "problems-with-hard-boundary-constraints"]], "Quadrature Functions": [[6, "quadrature-functions"]], "Reading all input parameters": [[36, "reading-all-input-parameters"], [37, "reading-all-input-parameters"], [38, "reading-all-input-parameters"], [39, "reading-all-input-parameters"]], "Reading the Input File": [[40, "reading-the-input-file"], [41, "reading-the-input-file"], [42, "reading-the-input-file"], [43, "reading-the-input-file"], [44, "reading-the-input-file"]], "Reading the boundary conditions and values": [[40, "reading-the-boundary-conditions-and-values"], [41, "reading-the-boundary-conditions-and-values"], [42, "reading-the-boundary-conditions-and-values"], [43, "reading-the-boundary-conditions-and-values"], [44, "reading-the-boundary-conditions-and-values"]], "Reading the input file": [[36, "reading-the-input-file"], [37, "reading-the-input-file"], [38, "reading-the-input-file"], [39, "reading-the-input-file"]], "References": [[36, "references"], [37, "references"], [38, "references"], [39, "references"], [40, "references"], [41, "references"], [42, "references"], [43, "references"], [44, "references"]], "Set up the geometry": [[36, "set-up-the-geometry"], [37, "set-up-the-geometry"], [38, "set-up-the-geometry"], [39, "set-up-the-geometry"]], "Setting up a Geometry_2D object": [[40, "setting-up-a-geometry-2d-object"], [41, "setting-up-a-geometry-2d-object"], [42, "setting-up-a-geometry-2d-object"], [43, "setting-up-a-geometry-2d-object"], [44, "setting-up-a-geometry-2d-object"]], "Setting up an Virtual Environment": [[2, "setting-up-an-virtual-environment"]], "Setting up the finite element space": [[40, "setting-up-the-finite-element-space"], [41, "setting-up-the-finite-element-space"], [42, "setting-up-the-finite-element-space"], [43, "setting-up-the-finite-element-space"], [44, "setting-up-the-finite-element-space"]], "Setup datahandler": [[36, "setup-datahandler"], [37, "setup-datahandler"], [38, "setup-datahandler"], [39, "setup-datahandler"]], "Setup fespace": [[36, "setup-fespace"], [37, "setup-fespace"], [38, "setup-fespace"], [39, "setup-fespace"]], "Setup model": [[36, "setup-model"], [37, "setup-model"], [38, "setup-model"], [39, "setup-model"]], "Solution": [[40, "solution"], [41, "solution"], [42, "solution"], [43, "solution"], [44, "solution"]], "Solution Plots": [[36, "solution-plots"], [37, "solution-plots"], [38, "solution-plots"], [39, "solution-plots"]], "Solving Inverse Problems with FastVPINNs : Estimation of spatially varying parameter on a complex geometry.": [[44, "solving-inverse-problems-with-fastvpinns-estimation-of-spatially-varying-parameter-on-a-complex-geometry"]], "Solving Inverse Problems with FastVPINNs : Estimation of uniform diffusion parameter on a quadrilateral geometry.": [[43, "solving-inverse-problems-with-fastvpinns-estimation-of-uniform-diffusion-parameter-on-a-quadrilateral-geometry"]], "Solving forward problems with FastVPINNs : Enforcing hard boundary constraints with an ansatz function.": [[40, "solving-forward-problems-with-fastvpinns-enforcing-hard-boundary-constraints-with-an-ansatz-function"]], "Solving forward problems with FastVPINNs : Helmholtz - 2D": [[41, "solving-forward-problems-with-fastvpinns-helmholtz-2d"]], "Solving forward problems with FastVPINNs : Poisson - 2D": [[42, "solving-forward-problems-with-fastvpinns-poisson-2d"]], "Steps to run the code": [[36, "steps-to-run-the-code"], [37, "steps-to-run-the-code"], [38, "steps-to-run-the-code"], [39, "steps-to-run-the-code"]], "Training": [[36, "training"], [37, "training"], [38, "training"], [39, "training"]], "Training the model": [[40, "training-the-model"]], "Utils": [[6, "utils"]], "Variational Physics-informed neural network": [[45, "variational-physics-informed-neural-network"]], "Welcome to FastVPINNs\u2019s documentation!": [[45, "welcome-to-fastvpinns-s-documentation"]], "fastvpinns": [[35, "fastvpinns"]], "fastvpinns.FE.FE2D_Cell module": [[12, "module-fastvpinns.FE.FE2D_Cell"]], "fastvpinns.FE.basis_2d_QN_Jacobi module": [[10, "module-fastvpinns.FE.basis_2d_QN_Jacobi"], [15, "module-fastvpinns.FE.basis_2d_QN_Jacobi"]], "fastvpinns.FE.fe2d_setup_main module": [[13, "module-fastvpinns.FE.fe2d_setup_main"]], "fastvpinns.FE.fe_transformation_2d module": [[18, "module-fastvpinns.FE.fe_transformation_2d"]], "fastvpinns.FE.fespace module": [[19, "module-fastvpinns.FE.fespace"]], "fastvpinns.FE.fespace2d module": [[14, "module-fastvpinns.FE.fespace2d"]], "fastvpinns.FE.quad_affine module": [[9, "module-fastvpinns.FE.quad_affine"]], "fastvpinns.FE.quad_bilinear module": [[11, "module-fastvpinns.FE.quad_bilinear"]], "fastvpinns.FE.quadratureformulas module": [[16, "module-fastvpinns.FE.quadratureformulas"]], "fastvpinns.FE.quadratureformulas_quad2d module": [[17, "module-fastvpinns.FE.quadratureformulas_quad2d"]], "fastvpinns.Geometry.geometry module": [[20, "module-fastvpinns.Geometry.geometry"]], "fastvpinns.Geometry.geometry_2d module": [[21, "module-fastvpinns.Geometry.geometry_2d"]], "fastvpinns.data.datahandler module": [[7, "module-fastvpinns.data.datahandler"]], "fastvpinns.data.datahandler2d module": [[8, "module-fastvpinns.data.datahandler2d"]], "fastvpinns.model.model module": [[22, "module-fastvpinns.model.model"]], "fastvpinns.model.model_hard module": [[23, "module-fastvpinns.model.model_hard"]], "fastvpinns.model.model_inverse module": [[24, "module-fastvpinns.model.model_inverse"]], "fastvpinns.model.model_inverse_domain module": [[25, "module-fastvpinns.model.model_inverse_domain"]], "fastvpinns.physics.cd2d module": [[26, "module-fastvpinns.physics.cd2d"]], "fastvpinns.physics.cd2d_inverse module": [[27, "module-fastvpinns.physics.cd2d_inverse"]], "fastvpinns.physics.cd2d_inverse_domain module": [[28, "module-fastvpinns.physics.cd2d_inverse_domain"]], "fastvpinns.physics.helmholtz2d module": [[29, "module-fastvpinns.physics.helmholtz2d"]], "fastvpinns.physics.poisson2d module": [[30, "module-fastvpinns.physics.poisson2d"]], "fastvpinns.physics.poisson2d_inverse module": [[31, "module-fastvpinns.physics.poisson2d_inverse"]], "fastvpinns.utils.compute_utils module": [[32, "module-fastvpinns.utils.compute_utils"]], "fastvpinns.utils.plot_utils module": [[33, "module-fastvpinns.utils.plot_utils"]], "fastvpinns.utils.print_utils module": [[34, "module-fastvpinns.utils.print_utils"]], "fe": [[40, "fe"], [41, "fe"], [42, "fe"], [43, "fe"], [44, "fe"]], "geometry": [[40, "geometry"], [41, "geometry"], [42, "geometry"], [43, "geometry"], [44, "geometry"]], "imports from fastvpinns": [[36, "imports-from-fastvpinns"], [37, "imports-from-fastvpinns"], [38, "imports-from-fastvpinns"], [39, "imports-from-fastvpinns"]], "inverse": [[43, "inverse"], [44, "inverse"]], "logging": [[36, "logging"], [37, "logging"], [38, "logging"], [39, "logging"], [40, "logging"], [41, "logging"], [42, "logging"], [43, "logging"], [44, "logging"]], "model": [[36, "model"], [37, "model"], [38, "model"], [39, "model"], [40, "model"], [41, "model"], [42, "model"], [43, "model"], [44, "model"]], "pde": [[36, "pde"], [37, "pde"], [38, "pde"], [39, "pde"], [40, "pde"], [41, "pde"], [42, "pde"], [43, "pde"], [44, "pde"]], "save the outputs": [[36, "save-the-outputs"], [37, "save-the-outputs"], [38, "save-the-outputs"], [39, "save-the-outputs"]]}, "docnames": ["_rst/_cite", "_rst/_contributing", "_rst/_installation", "_rst/_licence", "_rst/_team", "_rst/_tutorial", "_rst/fastvpinns", "_rst/library/data/datahandler", "_rst/library/data/datahandler2d", "_rst/library/fe2d/fe2d_affine_transformation", "_rst/library/fe2d/fe2d_basis_function", "_rst/library/fe2d/fe2d_bilinear_transformation", "_rst/library/fe2d/fe2d_fe2d_cell", "_rst/library/fe2d/fe2d_fe2d_setup", "_rst/library/fe2d/fe2d_fespace2d", "_rst/library/fe2d/fe2d_jacobi", "_rst/library/fe2d/fe2d_quadratureformulas", "_rst/library/fe2d/fe2d_quadratureformulas2d", "_rst/library/fe2d/fe2d_transformation", "_rst/library/fe2d/fespace", "_rst/library/geometry/geometry", "_rst/library/geometry/geometry2d", "_rst/library/model/model", "_rst/library/model/model_hard", "_rst/library/model/model_inverse", "_rst/library/model/model_inverse_domain", "_rst/library/physics/cd2d", "_rst/library/physics/cd2d_inverse", "_rst/library/physics/cd2d_inverse_domain", "_rst/library/physics/helmholtz2d", "_rst/library/physics/poisson2d", "_rst/library/physics/poisson2d_inverse", "_rst/library/utils/compute_utils", "_rst/library/utils/plot_utils", "_rst/library/utils/print_utils", "_rst/modules", "_rst/tutorials/forward_problems_2d/complex_mesh/cd2d/cd2d", "_rst/tutorials/forward_problems_2d/complex_mesh/cd2d_gear/cd2d_gear", "_rst/tutorials/forward_problems_2d/complex_mesh/helmholtz2d/helmholtz2d", "_rst/tutorials/forward_problems_2d/complex_mesh/poisson2d/poisson2d", "_rst/tutorials/forward_problems_2d/hard_boundary_constraints/poisson_2d/poisson2d_hard", "_rst/tutorials/forward_problems_2d/uniform_mesh/helmholtz_2d/helmholtz2d_uniform", "_rst/tutorials/forward_problems_2d/uniform_mesh/poisson_2d/poisson2d_uniform", "_rst/tutorials/inverse_problems_2d/const_inverse_poisson2d/inverse_constant", "_rst/tutorials/inverse_problems_2d/domain_inverse_cd2d/domain_inverse", "index"], "envversion": {"sphinx": 61, "sphinx.domains.c": 3, "sphinx.domains.changeset": 1, "sphinx.domains.citation": 1, "sphinx.domains.cpp": 9, "sphinx.domains.index": 1, "sphinx.domains.javascript": 3, "sphinx.domains.math": 2, "sphinx.domains.python": 4, "sphinx.domains.rst": 2, "sphinx.domains.std": 2, "sphinx.ext.intersphinx": 1, "sphinx.ext.todo": 2, "sphinx.ext.viewcode": 1}, "filenames": ["_rst/_cite.rst", "_rst/_contributing.rst", "_rst/_installation.rst", "_rst/_licence.rst", "_rst/_team.rst", "_rst/_tutorial.rst", "_rst/fastvpinns.rst", "_rst/library/data/datahandler.rst", "_rst/library/data/datahandler2d.rst", "_rst/library/fe2d/fe2d_affine_transformation.rst", "_rst/library/fe2d/fe2d_basis_function.rst", "_rst/library/fe2d/fe2d_bilinear_transformation.rst", "_rst/library/fe2d/fe2d_fe2d_cell.rst", "_rst/library/fe2d/fe2d_fe2d_setup.rst", "_rst/library/fe2d/fe2d_fespace2d.rst", "_rst/library/fe2d/fe2d_jacobi.rst", "_rst/library/fe2d/fe2d_quadratureformulas.rst", "_rst/library/fe2d/fe2d_quadratureformulas2d.rst", "_rst/library/fe2d/fe2d_transformation.rst", "_rst/library/fe2d/fespace.rst", "_rst/library/geometry/geometry.rst", "_rst/library/geometry/geometry2d.rst", "_rst/library/model/model.rst", "_rst/library/model/model_hard.rst", "_rst/library/model/model_inverse.rst", "_rst/library/model/model_inverse_domain.rst", "_rst/library/physics/cd2d.rst", "_rst/library/physics/cd2d_inverse.rst", "_rst/library/physics/cd2d_inverse_domain.rst", "_rst/library/physics/helmholtz2d.rst", "_rst/library/physics/poisson2d.rst", "_rst/library/physics/poisson2d_inverse.rst", "_rst/library/utils/compute_utils.rst", "_rst/library/utils/plot_utils.rst", "_rst/library/utils/print_utils.rst", "_rst/modules.rst", "_rst/tutorials/forward_problems_2d/complex_mesh/cd2d/cd2d.rst", "_rst/tutorials/forward_problems_2d/complex_mesh/cd2d_gear/cd2d_gear.rst", "_rst/tutorials/forward_problems_2d/complex_mesh/helmholtz2d/helmholtz2d.rst", "_rst/tutorials/forward_problems_2d/complex_mesh/poisson2d/poisson2d.rst", "_rst/tutorials/forward_problems_2d/hard_boundary_constraints/poisson_2d/poisson2d_hard.rst", "_rst/tutorials/forward_problems_2d/uniform_mesh/helmholtz_2d/helmholtz2d_uniform.rst", "_rst/tutorials/forward_problems_2d/uniform_mesh/poisson_2d/poisson2d_uniform.rst", "_rst/tutorials/inverse_problems_2d/const_inverse_poisson2d/inverse_constant.rst", "_rst/tutorials/inverse_problems_2d/domain_inverse_cd2d/domain_inverse.rst", "index.rst"], "indexentries": {"assign_basis_function() (fastvpinns.fe.fe2d_cell.fe2d_cell method)": [[12, "fastvpinns.FE.FE2D_Cell.FE2D_Cell.assign_basis_function", false]], "assign_basis_function() (fastvpinns.fe.fe2d_setup_main.fe2dsetupmain method)": [[13, "fastvpinns.FE.fe2d_setup_main.FE2DSetupMain.assign_basis_function", false]], "assign_basis_values_at_quadrature_points() (fastvpinns.fe.fe2d_cell.fe2d_cell method)": [[12, "fastvpinns.FE.FE2D_Cell.FE2D_Cell.assign_basis_values_at_quadrature_points", false]], "assign_fe_transformation() (fastvpinns.fe.fe2d_cell.fe2d_cell method)": [[12, "fastvpinns.FE.FE2D_Cell.FE2D_Cell.assign_fe_transformation", false]], "assign_fe_transformation() (fastvpinns.fe.fe2d_setup_main.fe2dsetupmain method)": [[13, "fastvpinns.FE.fe2d_setup_main.FE2DSetupMain.assign_fe_transformation", false]], "assign_forcing_term() (fastvpinns.fe.fe2d_cell.fe2d_cell method)": [[12, "fastvpinns.FE.FE2D_Cell.FE2D_Cell.assign_forcing_term", false]], "assign_quad_weights_and_jacobian() (fastvpinns.fe.fe2d_cell.fe2d_cell method)": [[12, "fastvpinns.FE.FE2D_Cell.FE2D_Cell.assign_quad_weights_and_jacobian", false]], "assign_quadrature() (fastvpinns.fe.fe2d_cell.fe2d_cell method)": [[12, "fastvpinns.FE.FE2D_Cell.FE2D_Cell.assign_quadrature", false]], "assign_quadrature_coordinates() (fastvpinns.fe.fe2d_cell.fe2d_cell method)": [[12, "fastvpinns.FE.FE2D_Cell.FE2D_Cell.assign_quadrature_coordinates", false]], "assign_quadrature_rules() (fastvpinns.fe.fe2d_setup_main.fe2dsetupmain method)": [[13, "fastvpinns.FE.fe2d_setup_main.FE2DSetupMain.assign_quadrature_rules", false]], "basis2dqnjacobi (class in fastvpinns.fe.basis_2d_qn_jacobi)": [[10, "fastvpinns.FE.basis_2d_QN_Jacobi.Basis2DQNJacobi", false], [15, "fastvpinns.FE.basis_2d_QN_Jacobi.Basis2DQNJacobi", false]], "call() (fastvpinns.model.model.densemodel method)": [[22, "fastvpinns.model.model.DenseModel.call", false]], "call() (fastvpinns.model.model_hard.densemodel_hard method)": [[23, "fastvpinns.model.model_hard.DenseModel_Hard.call", false], [23, "id0", false]], "call() (fastvpinns.model.model_inverse.densemodel_inverse method)": [[24, "fastvpinns.model.model_inverse.DenseModel_Inverse.call", false]], "call() (fastvpinns.model.model_inverse_domain.densemodel_inverse_domain method)": [[25, "fastvpinns.model.model_inverse_domain.DenseModel_Inverse_Domain.call", false]], "compute_errors_combined() (in module fastvpinns.utils.compute_utils)": [[32, "fastvpinns.utils.compute_utils.compute_errors_combined", false]], "compute_l1_error() (in module fastvpinns.utils.compute_utils)": [[32, "fastvpinns.utils.compute_utils.compute_l1_error", false]], "compute_l1_error_relative() (in module fastvpinns.utils.compute_utils)": [[32, "fastvpinns.utils.compute_utils.compute_l1_error_relative", false]], "compute_l2_error() (in module fastvpinns.utils.compute_utils)": [[32, "fastvpinns.utils.compute_utils.compute_l2_error", false]], "compute_l2_error_relative() (in module fastvpinns.utils.compute_utils)": [[32, "fastvpinns.utils.compute_utils.compute_l2_error_relative", false]], "compute_linf_error() (in module fastvpinns.utils.compute_utils)": [[32, "fastvpinns.utils.compute_utils.compute_linf_error", false]], "compute_linf_error_relative() (in module fastvpinns.utils.compute_utils)": [[32, "fastvpinns.utils.compute_utils.compute_linf_error_relative", false]], "datahandler (class in fastvpinns.data.datahandler)": [[7, "fastvpinns.data.datahandler.DataHandler", false]], "datahandler2d (class in fastvpinns.data.datahandler2d)": [[8, "fastvpinns.data.datahandler2d.DataHandler2D", false]], "ddtest_fcn() (fastvpinns.fe.basis_2d_qn_jacobi.basis2dqnjacobi method)": [[10, "fastvpinns.FE.basis_2d_QN_Jacobi.Basis2DQNJacobi.ddtest_fcn", false], [15, "fastvpinns.FE.basis_2d_QN_Jacobi.Basis2DQNJacobi.ddtest_fcn", false]], "densemodel (class in fastvpinns.model.model)": [[22, "fastvpinns.model.model.DenseModel", false]], "densemodel_hard (class in fastvpinns.model.model_hard)": [[23, "fastvpinns.model.model_hard.DenseModel_Hard", false]], "densemodel_inverse (class in fastvpinns.model.model_inverse)": [[24, "fastvpinns.model.model_inverse.DenseModel_Inverse", false]], "densemodel_inverse_domain (class in fastvpinns.model.model_inverse_domain)": [[25, "fastvpinns.model.model_inverse_domain.DenseModel_Inverse_Domain", false]], "djacobi() (fastvpinns.fe.basis_2d_qn_jacobi.basis2dqnjacobi method)": [[10, "fastvpinns.FE.basis_2d_QN_Jacobi.Basis2DQNJacobi.djacobi", false], [15, "fastvpinns.FE.basis_2d_QN_Jacobi.Basis2DQNJacobi.djacobi", false]], "dtest_fcn() (fastvpinns.fe.basis_2d_qn_jacobi.basis2dqnjacobi method)": [[10, "fastvpinns.FE.basis_2d_QN_Jacobi.Basis2DQNJacobi.dtest_fcn", false], [15, "fastvpinns.FE.basis_2d_QN_Jacobi.Basis2DQNJacobi.dtest_fcn", false]], "fastvpinns.data.datahandler": [[7, "module-fastvpinns.data.datahandler", false]], "fastvpinns.data.datahandler2d": [[8, "module-fastvpinns.data.datahandler2d", false]], "fastvpinns.fe.basis_2d_qn_jacobi": [[10, "module-fastvpinns.FE.basis_2d_QN_Jacobi", false], [15, "module-fastvpinns.FE.basis_2d_QN_Jacobi", false]], "fastvpinns.fe.fe2d_cell": [[12, "module-fastvpinns.FE.FE2D_Cell", false]], "fastvpinns.fe.fe2d_setup_main": [[13, "module-fastvpinns.FE.fe2d_setup_main", false]], "fastvpinns.fe.fe_transformation_2d": [[18, "module-fastvpinns.FE.fe_transformation_2d", false]], "fastvpinns.fe.fespace": [[19, "module-fastvpinns.FE.fespace", false]], "fastvpinns.fe.fespace2d": [[14, "module-fastvpinns.FE.fespace2d", false]], "fastvpinns.fe.quad_affine": [[9, "module-fastvpinns.FE.quad_affine", false]], "fastvpinns.fe.quad_bilinear": [[11, "module-fastvpinns.FE.quad_bilinear", false]], "fastvpinns.fe.quadratureformulas": [[16, "module-fastvpinns.FE.quadratureformulas", false]], "fastvpinns.fe.quadratureformulas_quad2d": [[17, "module-fastvpinns.FE.quadratureformulas_quad2d", false]], "fastvpinns.geometry.geometry": [[20, "module-fastvpinns.Geometry.geometry", false]], "fastvpinns.geometry.geometry_2d": [[21, "module-fastvpinns.Geometry.geometry_2d", false]], "fastvpinns.model.model": [[22, "module-fastvpinns.model.model", false]], "fastvpinns.model.model_hard": [[23, "module-fastvpinns.model.model_hard", false]], "fastvpinns.model.model_inverse": [[24, "module-fastvpinns.model.model_inverse", false]], "fastvpinns.model.model_inverse_domain": [[25, "module-fastvpinns.model.model_inverse_domain", false]], "fastvpinns.physics.cd2d": [[26, "module-fastvpinns.physics.cd2d", false]], "fastvpinns.physics.cd2d_inverse": [[27, "module-fastvpinns.physics.cd2d_inverse", false]], "fastvpinns.physics.cd2d_inverse_domain": [[28, "module-fastvpinns.physics.cd2d_inverse_domain", false]], "fastvpinns.physics.helmholtz2d": [[29, "module-fastvpinns.physics.helmholtz2d", false]], "fastvpinns.physics.poisson2d": [[30, "module-fastvpinns.physics.poisson2d", false]], "fastvpinns.physics.poisson2d_inverse": [[31, "module-fastvpinns.physics.poisson2d_inverse", false]], "fastvpinns.utils.compute_utils": [[32, "module-fastvpinns.utils.compute_utils", false]], "fastvpinns.utils.plot_utils": [[33, "module-fastvpinns.utils.plot_utils", false]], "fastvpinns.utils.print_utils": [[34, "module-fastvpinns.utils.print_utils", false]], "fe2d_cell (class in fastvpinns.fe.fe2d_cell)": [[12, "fastvpinns.FE.FE2D_Cell.FE2D_Cell", false]], "fe2dsetupmain (class in fastvpinns.fe.fe2d_setup_main)": [[13, "fastvpinns.FE.fe2d_setup_main.FE2DSetupMain", false]], "fespace (class in fastvpinns.fe.fespace)": [[19, "fastvpinns.FE.fespace.Fespace", false]], "fespace2d (class in fastvpinns.fe.fespace2d)": [[14, "fastvpinns.FE.fespace2d.Fespace2D", false]], "fetransforamtion2d (class in fastvpinns.fe.fe_transformation_2d)": [[18, "fastvpinns.FE.fe_transformation_2d.FETransforamtion2D", false]], "generate_dirichlet_boundary_data() (fastvpinns.fe.fespace.fespace method)": [[19, "fastvpinns.FE.fespace.Fespace.generate_dirichlet_boundary_data", false]], "generate_dirichlet_boundary_data() (fastvpinns.fe.fespace2d.fespace2d method)": [[14, "fastvpinns.FE.fespace2d.Fespace2D.generate_dirichlet_boundary_data", false]], "generate_dirichlet_boundary_data_vector() (fastvpinns.fe.fespace2d.fespace2d method)": [[14, "fastvpinns.FE.fespace2d.Fespace2D.generate_dirichlet_boundary_data_vector", false]], "generate_plot() (fastvpinns.fe.fespace2d.fespace2d method)": [[14, "fastvpinns.FE.fespace2d.Fespace2D.generate_plot", false]], "generate_quad_mesh_internal() (fastvpinns.geometry.geometry_2d.geometry_2d method)": [[21, "fastvpinns.Geometry.geometry_2d.Geometry_2D.generate_quad_mesh_internal", false]], "generate_vtk_for_test() (fastvpinns.geometry.geometry.geometry method)": [[20, "fastvpinns.Geometry.geometry.Geometry.generate_vtk_for_test", false]], "generate_vtk_for_test() (fastvpinns.geometry.geometry_2d.geometry_2d method)": [[21, "fastvpinns.Geometry.geometry_2d.Geometry_2D.generate_vtk_for_test", false]], "geometry (class in fastvpinns.geometry.geometry)": [[20, "fastvpinns.Geometry.geometry.Geometry", false]], "geometry_2d (class in fastvpinns.geometry.geometry_2d)": [[21, "fastvpinns.Geometry.geometry_2d.Geometry_2D", false]], "get_bilinear_params_dict_as_tensors() (fastvpinns.data.datahandler.datahandler method)": [[7, "fastvpinns.data.datahandler.DataHandler.get_bilinear_params_dict_as_tensors", false]], "get_bilinear_params_dict_as_tensors() (fastvpinns.data.datahandler2d.datahandler2d method)": [[8, "fastvpinns.data.datahandler2d.DataHandler2D.get_bilinear_params_dict_as_tensors", false]], "get_config() (fastvpinns.model.model.densemodel method)": [[22, "fastvpinns.model.model.DenseModel.get_config", false]], "get_config() (fastvpinns.model.model_hard.densemodel_hard method)": [[23, "fastvpinns.model.model_hard.DenseModel_Hard.get_config", false], [23, "id1", false]], "get_config() (fastvpinns.model.model_inverse.densemodel_inverse method)": [[24, "fastvpinns.model.model_inverse.DenseModel_Inverse.get_config", false]], "get_config() (fastvpinns.model.model_inverse_domain.densemodel_inverse_domain method)": [[25, "fastvpinns.model.model_inverse_domain.DenseModel_Inverse_Domain.get_config", false]], "get_dirichlet_input() (fastvpinns.data.datahandler.datahandler method)": [[7, "fastvpinns.data.datahandler.DataHandler.get_dirichlet_input", false]], "get_dirichlet_input() (fastvpinns.data.datahandler2d.datahandler2d method)": [[8, "fastvpinns.data.datahandler2d.DataHandler2D.get_dirichlet_input", false]], "get_forcing_function_values() (fastvpinns.fe.fespace.fespace method)": [[19, "fastvpinns.FE.fespace.Fespace.get_forcing_function_values", false]], "get_forcing_function_values() (fastvpinns.fe.fespace2d.fespace2d method)": [[14, "fastvpinns.FE.fespace2d.Fespace2D.get_forcing_function_values", false]], "get_forcing_function_values_vector() (fastvpinns.fe.fespace2d.fespace2d method)": [[14, "fastvpinns.FE.fespace2d.Fespace2D.get_forcing_function_values_vector", false]], "get_inverse_params() (fastvpinns.data.datahandler.datahandler method)": [[7, "fastvpinns.data.datahandler.DataHandler.get_inverse_params", false]], "get_inverse_params() (fastvpinns.data.datahandler2d.datahandler2d method)": [[8, "fastvpinns.data.datahandler2d.DataHandler2D.get_inverse_params", false]], "get_jacobian() (fastvpinns.fe.fe_transformation_2d.fetransforamtion2d method)": [[18, "fastvpinns.FE.fe_transformation_2d.FETransforamtion2D.get_jacobian", false]], "get_jacobian() (fastvpinns.fe.quad_affine.quadaffin method)": [[9, "fastvpinns.FE.quad_affine.QuadAffin.get_jacobian", false]], "get_jacobian() (fastvpinns.fe.quad_bilinear.quadbilinear method)": [[11, "fastvpinns.FE.quad_bilinear.QuadBilinear.get_jacobian", false]], "get_num_quad_points() (fastvpinns.fe.quadratureformulas.quadratureformulas method)": [[16, "fastvpinns.FE.quadratureformulas.Quadratureformulas.get_num_quad_points", false]], "get_num_quad_points() (fastvpinns.fe.quadratureformulas_quad2d.quadratureformulas_quad2d method)": [[17, "fastvpinns.FE.quadratureformulas_quad2d.Quadratureformulas_Quad2D.get_num_quad_points", false]], "get_orig_from_ref_derivative() (fastvpinns.fe.quad_affine.quadaffin method)": [[9, "fastvpinns.FE.quad_affine.QuadAffin.get_orig_from_ref_derivative", false]], "get_orig_from_ref_derivative() (fastvpinns.fe.quad_bilinear.quadbilinear method)": [[11, "fastvpinns.FE.quad_bilinear.QuadBilinear.get_orig_from_ref_derivative", false]], "get_orig_from_ref_second_derivative() (fastvpinns.fe.quad_affine.quadaffin method)": [[9, "fastvpinns.FE.quad_affine.QuadAffin.get_orig_from_ref_second_derivative", false]], "get_orig_from_ref_second_derivative() (fastvpinns.fe.quad_bilinear.quadbilinear method)": [[11, "fastvpinns.FE.quad_bilinear.QuadBilinear.get_orig_from_ref_second_derivative", false]], "get_original_from_ref() (fastvpinns.fe.fe_transformation_2d.fetransforamtion2d method)": [[18, "fastvpinns.FE.fe_transformation_2d.FETransforamtion2D.get_original_from_ref", false]], "get_original_from_ref() (fastvpinns.fe.quad_affine.quadaffin method)": [[9, "fastvpinns.FE.quad_affine.QuadAffin.get_original_from_ref", false]], "get_original_from_ref() (fastvpinns.fe.quad_bilinear.quadbilinear method)": [[11, "fastvpinns.FE.quad_bilinear.QuadBilinear.get_original_from_ref", false]], "get_quad_values() (fastvpinns.fe.quadratureformulas.quadratureformulas method)": [[16, "fastvpinns.FE.quadratureformulas.Quadratureformulas.get_quad_values", false]], "get_quad_values() (fastvpinns.fe.quadratureformulas_quad2d.quadratureformulas_quad2d method)": [[17, "fastvpinns.FE.quadratureformulas_quad2d.Quadratureformulas_Quad2D.get_quad_values", false]], "get_quadrature_actual_coordinates() (fastvpinns.fe.fespace.fespace method)": [[19, "fastvpinns.FE.fespace.Fespace.get_quadrature_actual_coordinates", false]], "get_quadrature_actual_coordinates() (fastvpinns.fe.fespace2d.fespace2d method)": [[14, "fastvpinns.FE.fespace2d.Fespace2D.get_quadrature_actual_coordinates", false]], "get_quadrature_weights() (fastvpinns.fe.fespace2d.fespace2d method)": [[14, "fastvpinns.FE.fespace2d.Fespace2D.get_quadrature_weights", false]], "get_sensor_data() (fastvpinns.data.datahandler.datahandler method)": [[7, "fastvpinns.data.datahandler.DataHandler.get_sensor_data", false]], "get_sensor_data() (fastvpinns.data.datahandler2d.datahandler2d method)": [[8, "fastvpinns.data.datahandler2d.DataHandler2D.get_sensor_data", false]], "get_sensor_data() (fastvpinns.fe.fespace.fespace method)": [[19, "fastvpinns.FE.fespace.Fespace.get_sensor_data", false]], "get_sensor_data() (fastvpinns.fe.fespace2d.fespace2d method)": [[14, "fastvpinns.FE.fespace2d.Fespace2D.get_sensor_data", false]], "get_sensor_data_external() (fastvpinns.fe.fespace.fespace method)": [[19, "fastvpinns.FE.fespace.Fespace.get_sensor_data_external", false]], "get_sensor_data_external() (fastvpinns.fe.fespace2d.fespace2d method)": [[14, "fastvpinns.FE.fespace2d.Fespace2D.get_sensor_data_external", false]], "get_shape_function_grad_x() (fastvpinns.fe.fespace.fespace method)": [[19, "fastvpinns.FE.fespace.Fespace.get_shape_function_grad_x", false]], "get_shape_function_grad_x() (fastvpinns.fe.fespace2d.fespace2d method)": [[14, "fastvpinns.FE.fespace2d.Fespace2D.get_shape_function_grad_x", false]], "get_shape_function_grad_x_ref() (fastvpinns.fe.fespace.fespace method)": [[19, "fastvpinns.FE.fespace.Fespace.get_shape_function_grad_x_ref", false]], "get_shape_function_grad_x_ref() (fastvpinns.fe.fespace2d.fespace2d method)": [[14, "fastvpinns.FE.fespace2d.Fespace2D.get_shape_function_grad_x_ref", false]], "get_shape_function_grad_y() (fastvpinns.fe.fespace.fespace method)": [[19, "fastvpinns.FE.fespace.Fespace.get_shape_function_grad_y", false]], "get_shape_function_grad_y() (fastvpinns.fe.fespace2d.fespace2d method)": [[14, "fastvpinns.FE.fespace2d.Fespace2D.get_shape_function_grad_y", false]], "get_shape_function_grad_y_ref() (fastvpinns.fe.fespace.fespace method)": [[19, "fastvpinns.FE.fespace.Fespace.get_shape_function_grad_y_ref", false]], "get_shape_function_grad_y_ref() (fastvpinns.fe.fespace2d.fespace2d method)": [[14, "fastvpinns.FE.fespace2d.Fespace2D.get_shape_function_grad_y_ref", false]], "get_shape_function_val() (fastvpinns.fe.fespace.fespace method)": [[19, "fastvpinns.FE.fespace.Fespace.get_shape_function_val", false]], "get_shape_function_val() (fastvpinns.fe.fespace2d.fespace2d method)": [[14, "fastvpinns.FE.fespace2d.Fespace2D.get_shape_function_val", false]], "get_test_points() (fastvpinns.data.datahandler.datahandler method)": [[7, "fastvpinns.data.datahandler.DataHandler.get_test_points", false]], "get_test_points() (fastvpinns.data.datahandler2d.datahandler2d method)": [[8, "fastvpinns.data.datahandler2d.DataHandler2D.get_test_points", false]], "get_test_points() (fastvpinns.geometry.geometry.geometry method)": [[20, "fastvpinns.Geometry.geometry.Geometry.get_test_points", false]], "get_test_points() (fastvpinns.geometry.geometry_2d.geometry_2d method)": [[21, "fastvpinns.Geometry.geometry_2d.Geometry_2D.get_test_points", false]], "gradx() (fastvpinns.fe.basis_2d_qn_jacobi.basis2dqnjacobi method)": [[10, "fastvpinns.FE.basis_2d_QN_Jacobi.Basis2DQNJacobi.gradx", false], [15, "fastvpinns.FE.basis_2d_QN_Jacobi.Basis2DQNJacobi.gradx", false]], "gradxx() (fastvpinns.fe.basis_2d_qn_jacobi.basis2dqnjacobi method)": [[10, "fastvpinns.FE.basis_2d_QN_Jacobi.Basis2DQNJacobi.gradxx", false], [15, "fastvpinns.FE.basis_2d_QN_Jacobi.Basis2DQNJacobi.gradxx", false]], "gradxy() (fastvpinns.fe.basis_2d_qn_jacobi.basis2dqnjacobi method)": [[10, "fastvpinns.FE.basis_2d_QN_Jacobi.Basis2DQNJacobi.gradxy", false], [15, "fastvpinns.FE.basis_2d_QN_Jacobi.Basis2DQNJacobi.gradxy", false]], "grady() (fastvpinns.fe.basis_2d_qn_jacobi.basis2dqnjacobi method)": [[10, "fastvpinns.FE.basis_2d_QN_Jacobi.Basis2DQNJacobi.grady", false], [15, "fastvpinns.FE.basis_2d_QN_Jacobi.Basis2DQNJacobi.grady", false]], "gradyy() (fastvpinns.fe.basis_2d_qn_jacobi.basis2dqnjacobi method)": [[10, "fastvpinns.FE.basis_2d_QN_Jacobi.Basis2DQNJacobi.gradyy", false], [15, "fastvpinns.FE.basis_2d_QN_Jacobi.Basis2DQNJacobi.gradyy", false]], "jacobi_wrapper() (fastvpinns.fe.basis_2d_qn_jacobi.basis2dqnjacobi method)": [[10, "fastvpinns.FE.basis_2d_QN_Jacobi.Basis2DQNJacobi.jacobi_wrapper", false], [15, "fastvpinns.FE.basis_2d_QN_Jacobi.Basis2DQNJacobi.jacobi_wrapper", false]], "module": [[7, "module-fastvpinns.data.datahandler", false], [8, "module-fastvpinns.data.datahandler2d", false], [9, "module-fastvpinns.FE.quad_affine", false], [10, "module-fastvpinns.FE.basis_2d_QN_Jacobi", false], [11, "module-fastvpinns.FE.quad_bilinear", false], [12, "module-fastvpinns.FE.FE2D_Cell", false], [13, "module-fastvpinns.FE.fe2d_setup_main", false], [14, "module-fastvpinns.FE.fespace2d", false], [15, "module-fastvpinns.FE.basis_2d_QN_Jacobi", false], [16, "module-fastvpinns.FE.quadratureformulas", false], [17, "module-fastvpinns.FE.quadratureformulas_quad2d", false], [18, "module-fastvpinns.FE.fe_transformation_2d", false], [19, "module-fastvpinns.FE.fespace", false], [20, "module-fastvpinns.Geometry.geometry", false], [21, "module-fastvpinns.Geometry.geometry_2d", false], [22, "module-fastvpinns.model.model", false], [23, "module-fastvpinns.model.model_hard", false], [24, "module-fastvpinns.model.model_inverse", false], [25, "module-fastvpinns.model.model_inverse_domain", false], [26, "module-fastvpinns.physics.cd2d", false], [27, "module-fastvpinns.physics.cd2d_inverse", false], [28, "module-fastvpinns.physics.cd2d_inverse_domain", false], [29, "module-fastvpinns.physics.helmholtz2d", false], [30, "module-fastvpinns.physics.poisson2d", false], [31, "module-fastvpinns.physics.poisson2d_inverse", false], [32, "module-fastvpinns.utils.compute_utils", false], [33, "module-fastvpinns.utils.plot_utils", false], [34, "module-fastvpinns.utils.print_utils", false]], "pde_loss_cd2d() (in module fastvpinns.physics.cd2d)": [[26, "fastvpinns.physics.cd2d.pde_loss_cd2d", false]], "pde_loss_cd2d() (in module fastvpinns.physics.cd2d_inverse)": [[27, "fastvpinns.physics.cd2d_inverse.pde_loss_cd2d", false]], "pde_loss_cd2d_inverse_domain() (in module fastvpinns.physics.cd2d_inverse_domain)": [[28, "fastvpinns.physics.cd2d_inverse_domain.pde_loss_cd2d_inverse_domain", false]], "pde_loss_helmholtz() (in module fastvpinns.physics.helmholtz2d)": [[29, "fastvpinns.physics.helmholtz2d.pde_loss_helmholtz", false]], "pde_loss_poisson() (in module fastvpinns.physics.poisson2d)": [[30, "fastvpinns.physics.poisson2d.pde_loss_poisson", false]], "pde_loss_poisson_inverse() (in module fastvpinns.physics.poisson2d_inverse)": [[31, "fastvpinns.physics.poisson2d_inverse.pde_loss_poisson_inverse", false]], "plot_adaptive_mesh() (fastvpinns.geometry.geometry_2d.geometry_2d method)": [[21, "fastvpinns.Geometry.geometry_2d.Geometry_2D.plot_adaptive_mesh", false]], "plot_array() (in module fastvpinns.utils.plot_utils)": [[33, "fastvpinns.utils.plot_utils.plot_array", false]], "plot_contour() (in module fastvpinns.utils.plot_utils)": [[33, "fastvpinns.utils.plot_utils.plot_contour", false]], "plot_inverse_param_function() (in module fastvpinns.utils.plot_utils)": [[33, "fastvpinns.utils.plot_utils.plot_inverse_param_function", false]], "plot_inverse_test_loss_function() (in module fastvpinns.utils.plot_utils)": [[33, "fastvpinns.utils.plot_utils.plot_inverse_test_loss_function", false]], "plot_loss_function() (in module fastvpinns.utils.plot_utils)": [[33, "fastvpinns.utils.plot_utils.plot_loss_function", false]], "plot_multiple_loss_function() (in module fastvpinns.utils.plot_utils)": [[33, "fastvpinns.utils.plot_utils.plot_multiple_loss_function", false]], "plot_test_loss_function() (in module fastvpinns.utils.plot_utils)": [[33, "fastvpinns.utils.plot_utils.plot_test_loss_function", false]], "plot_test_time_loss_function() (in module fastvpinns.utils.plot_utils)": [[33, "fastvpinns.utils.plot_utils.plot_test_time_loss_function", false]], "print_table() (in module fastvpinns.utils.print_utils)": [[34, "fastvpinns.utils.print_utils.print_table", false]], "quadaffin (class in fastvpinns.fe.quad_affine)": [[9, "fastvpinns.FE.quad_affine.QuadAffin", false]], "quadbilinear (class in fastvpinns.fe.quad_bilinear)": [[11, "fastvpinns.FE.quad_bilinear.QuadBilinear", false]], "quadratureformulas (class in fastvpinns.fe.quadratureformulas)": [[16, "fastvpinns.FE.quadratureformulas.Quadratureformulas", false]], "quadratureformulas_quad2d (class in fastvpinns.fe.quadratureformulas_quad2d)": [[17, "fastvpinns.FE.quadratureformulas_quad2d.Quadratureformulas_Quad2D", false]], "read_mesh() (fastvpinns.geometry.geometry.geometry method)": [[20, "fastvpinns.Geometry.geometry.Geometry.read_mesh", false]], "read_mesh() (fastvpinns.geometry.geometry_2d.geometry_2d method)": [[21, "fastvpinns.Geometry.geometry_2d.Geometry_2D.read_mesh", false]], "set_cell() (fastvpinns.fe.fe_transformation_2d.fetransforamtion2d method)": [[18, "fastvpinns.FE.fe_transformation_2d.FETransforamtion2D.set_cell", false]], "set_cell() (fastvpinns.fe.quad_affine.quadaffin method)": [[9, "fastvpinns.FE.quad_affine.QuadAffin.set_cell", false]], "set_cell() (fastvpinns.fe.quad_bilinear.quadbilinear method)": [[11, "fastvpinns.FE.quad_bilinear.QuadBilinear.set_cell", false]], "set_finite_elements() (fastvpinns.fe.fespace.fespace method)": [[19, "fastvpinns.FE.fespace.Fespace.set_finite_elements", false]], "set_finite_elements() (fastvpinns.fe.fespace2d.fespace2d method)": [[14, "fastvpinns.FE.fespace2d.Fespace2D.set_finite_elements", false]], "test_fcnx() (fastvpinns.fe.basis_2d_qn_jacobi.basis2dqnjacobi method)": [[10, "fastvpinns.FE.basis_2d_QN_Jacobi.Basis2DQNJacobi.test_fcnx", false], [15, "fastvpinns.FE.basis_2d_QN_Jacobi.Basis2DQNJacobi.test_fcnx", false]], "test_fcny() (fastvpinns.fe.basis_2d_qn_jacobi.basis2dqnjacobi method)": [[10, "fastvpinns.FE.basis_2d_QN_Jacobi.Basis2DQNJacobi.test_fcny", false], [15, "fastvpinns.FE.basis_2d_QN_Jacobi.Basis2DQNJacobi.test_fcny", false]], "train_step() (fastvpinns.model.model.densemodel method)": [[22, "fastvpinns.model.model.DenseModel.train_step", false]], "train_step() (fastvpinns.model.model_hard.densemodel_hard method)": [[23, "fastvpinns.model.model_hard.DenseModel_Hard.train_step", false], [23, "id2", false]], "train_step() (fastvpinns.model.model_inverse.densemodel_inverse method)": [[24, "fastvpinns.model.model_inverse.DenseModel_Inverse.train_step", false]], "train_step() (fastvpinns.model.model_inverse_domain.densemodel_inverse_domain method)": [[25, "fastvpinns.model.model_inverse_domain.DenseModel_Inverse_Domain.train_step", false]], "value() (fastvpinns.fe.basis_2d_qn_jacobi.basis2dqnjacobi method)": [[10, "fastvpinns.FE.basis_2d_QN_Jacobi.Basis2DQNJacobi.value", false], [15, "fastvpinns.FE.basis_2d_QN_Jacobi.Basis2DQNJacobi.value", false]], "write_vtk() (fastvpinns.geometry.geometry_2d.geometry_2d method)": [[21, "fastvpinns.Geometry.geometry_2d.Geometry_2D.write_vtk", false]]}, "objects": {"fastvpinns.FE": [[12, 0, 0, "-", "FE2D_Cell"], [15, 0, 0, "-", "basis_2d_QN_Jacobi"], [13, 0, 0, "-", "fe2d_setup_main"], [18, 0, 0, "-", "fe_transformation_2d"], [19, 0, 0, "-", "fespace"], [14, 0, 0, "-", "fespace2d"], [9, 0, 0, "-", "quad_affine"], [11, 0, 0, "-", "quad_bilinear"], [16, 0, 0, "-", "quadratureformulas"], [17, 0, 0, "-", "quadratureformulas_quad2d"]], "fastvpinns.FE.FE2D_Cell": [[12, 1, 1, "", "FE2D_Cell"]], "fastvpinns.FE.FE2D_Cell.FE2D_Cell": [[12, 2, 1, "", "assign_basis_function"], [12, 2, 1, "", "assign_basis_values_at_quadrature_points"], [12, 2, 1, "", "assign_fe_transformation"], [12, 2, 1, "", "assign_forcing_term"], [12, 2, 1, "", "assign_quad_weights_and_jacobian"], [12, 2, 1, "", "assign_quadrature"], [12, 2, 1, "", "assign_quadrature_coordinates"]], "fastvpinns.FE.basis_2d_QN_Jacobi": [[15, 1, 1, "", "Basis2DQNJacobi"]], "fastvpinns.FE.basis_2d_QN_Jacobi.Basis2DQNJacobi": [[15, 2, 1, "", "ddtest_fcn"], [15, 2, 1, "", "djacobi"], [15, 2, 1, "", "dtest_fcn"], [15, 2, 1, "", "gradx"], [15, 2, 1, "", "gradxx"], [15, 2, 1, "", "gradxy"], [15, 2, 1, "", "grady"], [15, 2, 1, "", "gradyy"], [15, 2, 1, "", "jacobi_wrapper"], [15, 2, 1, "", "test_fcnx"], [15, 2, 1, "", "test_fcny"], [15, 2, 1, "", "value"]], "fastvpinns.FE.fe2d_setup_main": [[13, 1, 1, "", "FE2DSetupMain"]], "fastvpinns.FE.fe2d_setup_main.FE2DSetupMain": [[13, 2, 1, "", "assign_basis_function"], [13, 2, 1, "", "assign_fe_transformation"], [13, 2, 1, "", "assign_quadrature_rules"]], "fastvpinns.FE.fe_transformation_2d": [[18, 1, 1, "", "FETransforamtion2D"]], "fastvpinns.FE.fe_transformation_2d.FETransforamtion2D": [[18, 2, 1, "", "get_jacobian"], [18, 2, 1, "", "get_original_from_ref"], [18, 2, 1, "", "set_cell"]], "fastvpinns.FE.fespace": [[19, 1, 1, "", "Fespace"]], "fastvpinns.FE.fespace.Fespace": [[19, 2, 1, "", "generate_dirichlet_boundary_data"], [19, 2, 1, "", "get_forcing_function_values"], [19, 2, 1, "", "get_quadrature_actual_coordinates"], [19, 2, 1, "", "get_sensor_data"], [19, 2, 1, "", "get_sensor_data_external"], [19, 2, 1, "", "get_shape_function_grad_x"], [19, 2, 1, "", "get_shape_function_grad_x_ref"], [19, 2, 1, "", "get_shape_function_grad_y"], [19, 2, 1, "", "get_shape_function_grad_y_ref"], [19, 2, 1, "", "get_shape_function_val"], [19, 2, 1, "", "set_finite_elements"]], "fastvpinns.FE.fespace2d": [[14, 1, 1, "", "Fespace2D"]], "fastvpinns.FE.fespace2d.Fespace2D": [[14, 2, 1, "", "generate_dirichlet_boundary_data"], [14, 2, 1, "", "generate_dirichlet_boundary_data_vector"], [14, 2, 1, "", "generate_plot"], [14, 2, 1, "", "get_forcing_function_values"], [14, 2, 1, "", "get_forcing_function_values_vector"], [14, 2, 1, "", "get_quadrature_actual_coordinates"], [14, 2, 1, "", "get_quadrature_weights"], [14, 2, 1, "", "get_sensor_data"], [14, 2, 1, "", "get_sensor_data_external"], [14, 2, 1, "", "get_shape_function_grad_x"], [14, 2, 1, "", "get_shape_function_grad_x_ref"], [14, 2, 1, "", "get_shape_function_grad_y"], [14, 2, 1, "", "get_shape_function_grad_y_ref"], [14, 2, 1, "", "get_shape_function_val"], [14, 2, 1, "", "set_finite_elements"]], "fastvpinns.FE.quad_affine": [[9, 1, 1, "", "QuadAffin"]], "fastvpinns.FE.quad_affine.QuadAffin": [[9, 2, 1, "", "get_jacobian"], [9, 2, 1, "", "get_orig_from_ref_derivative"], [9, 2, 1, "", "get_orig_from_ref_second_derivative"], [9, 2, 1, "", "get_original_from_ref"], [9, 2, 1, "", "set_cell"]], "fastvpinns.FE.quad_bilinear": [[11, 1, 1, "", "QuadBilinear"]], "fastvpinns.FE.quad_bilinear.QuadBilinear": [[11, 2, 1, "", "get_jacobian"], [11, 2, 1, "", "get_orig_from_ref_derivative"], [11, 2, 1, "", "get_orig_from_ref_second_derivative"], [11, 2, 1, "", "get_original_from_ref"], [11, 2, 1, "", "set_cell"]], "fastvpinns.FE.quadratureformulas": [[16, 1, 1, "", "Quadratureformulas"]], "fastvpinns.FE.quadratureformulas.Quadratureformulas": [[16, 2, 1, "", "get_num_quad_points"], [16, 2, 1, "", "get_quad_values"]], "fastvpinns.FE.quadratureformulas_quad2d": [[17, 1, 1, "", "Quadratureformulas_Quad2D"]], "fastvpinns.FE.quadratureformulas_quad2d.Quadratureformulas_Quad2D": [[17, 2, 1, "", "get_num_quad_points"], [17, 2, 1, "", "get_quad_values"]], "fastvpinns.Geometry": [[20, 0, 0, "-", "geometry"], [21, 0, 0, "-", "geometry_2d"]], "fastvpinns.Geometry.geometry": [[20, 1, 1, "", "Geometry"]], "fastvpinns.Geometry.geometry.Geometry": [[20, 2, 1, "", "generate_vtk_for_test"], [20, 2, 1, "", "get_test_points"], [20, 2, 1, "", "read_mesh"]], "fastvpinns.Geometry.geometry_2d": [[21, 1, 1, "", "Geometry_2D"]], "fastvpinns.Geometry.geometry_2d.Geometry_2D": [[21, 2, 1, "", "generate_quad_mesh_internal"], [21, 2, 1, "", "generate_vtk_for_test"], [21, 2, 1, "", "get_test_points"], [21, 2, 1, "", "plot_adaptive_mesh"], [21, 2, 1, "", "read_mesh"], [21, 2, 1, "", "write_vtk"]], "fastvpinns.data": [[7, 0, 0, "-", "datahandler"], [8, 0, 0, "-", "datahandler2d"]], "fastvpinns.data.datahandler": [[7, 1, 1, "", "DataHandler"]], "fastvpinns.data.datahandler.DataHandler": [[7, 2, 1, "", "get_bilinear_params_dict_as_tensors"], [7, 2, 1, "", "get_dirichlet_input"], [7, 2, 1, "", "get_inverse_params"], [7, 2, 1, "", "get_sensor_data"], [7, 2, 1, "", "get_test_points"]], "fastvpinns.data.datahandler2d": [[8, 1, 1, "", "DataHandler2D"]], "fastvpinns.data.datahandler2d.DataHandler2D": [[8, 2, 1, "", "get_bilinear_params_dict_as_tensors"], [8, 2, 1, "", "get_dirichlet_input"], [8, 2, 1, "", "get_inverse_params"], [8, 2, 1, "", "get_sensor_data"], [8, 2, 1, "", "get_test_points"]], "fastvpinns.model": [[22, 0, 0, "-", "model"], [23, 0, 0, "-", "model_hard"], [24, 0, 0, "-", "model_inverse"], [25, 0, 0, "-", "model_inverse_domain"]], "fastvpinns.model.model": [[22, 1, 1, "", "DenseModel"]], "fastvpinns.model.model.DenseModel": [[22, 2, 1, "", "call"], [22, 2, 1, "", "get_config"], [22, 2, 1, "", "train_step"]], "fastvpinns.model.model_hard": [[23, 1, 1, "", "DenseModel_Hard"]], "fastvpinns.model.model_hard.DenseModel_Hard": [[23, 2, 1, "id0", "call"], [23, 2, 1, "id1", "get_config"], [23, 2, 1, "id2", "train_step"]], "fastvpinns.model.model_inverse": [[24, 1, 1, "", "DenseModel_Inverse"]], "fastvpinns.model.model_inverse.DenseModel_Inverse": [[24, 2, 1, "", "call"], [24, 2, 1, "", "get_config"], [24, 2, 1, "", "train_step"]], "fastvpinns.model.model_inverse_domain": [[25, 1, 1, "", "DenseModel_Inverse_Domain"]], "fastvpinns.model.model_inverse_domain.DenseModel_Inverse_Domain": [[25, 2, 1, "", "call"], [25, 2, 1, "", "get_config"], [25, 2, 1, "", "train_step"]], "fastvpinns.physics": [[26, 0, 0, "-", "cd2d"], [27, 0, 0, "-", "cd2d_inverse"], [28, 0, 0, "-", "cd2d_inverse_domain"], [29, 0, 0, "-", "helmholtz2d"], [30, 0, 0, "-", "poisson2d"], [31, 0, 0, "-", "poisson2d_inverse"]], "fastvpinns.physics.cd2d": [[26, 3, 1, "", "pde_loss_cd2d"]], "fastvpinns.physics.cd2d_inverse": [[27, 3, 1, "", "pde_loss_cd2d"]], "fastvpinns.physics.cd2d_inverse_domain": [[28, 3, 1, "", "pde_loss_cd2d_inverse_domain"]], "fastvpinns.physics.helmholtz2d": [[29, 3, 1, "", "pde_loss_helmholtz"]], "fastvpinns.physics.poisson2d": [[30, 3, 1, "", "pde_loss_poisson"]], "fastvpinns.physics.poisson2d_inverse": [[31, 3, 1, "", "pde_loss_poisson_inverse"]], "fastvpinns.utils": [[32, 0, 0, "-", "compute_utils"], [33, 0, 0, "-", "plot_utils"], [34, 0, 0, "-", "print_utils"]], "fastvpinns.utils.compute_utils": [[32, 3, 1, "", "compute_errors_combined"], [32, 3, 1, "", "compute_l1_error"], [32, 3, 1, "", "compute_l1_error_relative"], [32, 3, 1, "", "compute_l2_error"], [32, 3, 1, "", "compute_l2_error_relative"], [32, 3, 1, "", "compute_linf_error"], [32, 3, 1, "", "compute_linf_error_relative"]], "fastvpinns.utils.plot_utils": [[33, 3, 1, "", "plot_array"], [33, 3, 1, "", "plot_contour"], [33, 3, 1, "", "plot_inverse_param_function"], [33, 3, 1, "", "plot_inverse_test_loss_function"], [33, 3, 1, "", "plot_loss_function"], [33, 3, 1, "", "plot_multiple_loss_function"], [33, 3, 1, "", "plot_test_loss_function"], [33, 3, 1, "", "plot_test_time_loss_function"]], "fastvpinns.utils.print_utils": [[34, 3, 1, "", "print_table"]]}, "objnames": {"0": ["py", "module", "Python module"], "1": ["py", "class", "Python class"], "2": ["py", "method", "Python method"], "3": ["py", "function", "Python function"]}, "objtypes": {"0": "py:module", "1": "py:class", "2": "py:method", "3": "py:function"}, "terms": {"": [36, 37, 38, 39, 40, 41, 42, 43, 44], "0": [14, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45], "001": [36, 38, 39], "005": 37, "01": 23, "02": [32, 33], "03": [19, 20], "04": 2, "1": [4, 10, 12, 14, 15, 32, 34, 36, 37, 38, 39, 40, 41, 42, 43, 44], "10": [2, 22, 23, 24, 25, 36, 37, 38, 39, 43, 44], "100": [36, 37, 38, 39], "1000": [36, 37, 38, 39, 40, 41, 42, 43, 44], "10000": [37, 38], "1001": [37, 40, 41, 42, 43], "1002": [40, 41, 42, 43], "1003": [40, 41, 42, 43], "10b": [36, 37, 38, 39], "11": [2, 32, 33], "12063": [0, 26, 27, 28, 29, 30, 31], "150000": 37, "16": [36, 39], "2": [10, 14, 15, 32, 34, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45], "20": [2, 43], "2000": [37, 39], "2023": [9, 10, 11, 14, 15, 21, 22, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33], "2024": [0, 3, 19, 20, 23], "21": [21, 26, 27, 28, 29, 30, 31], "22": [22, 23, 24, 25], "2404": [0, 26, 27, 28, 29, 30, 31], "25": [36, 37, 38, 39], "2d": [5, 6, 7, 8, 10, 14, 15, 16, 17, 18, 20, 21, 35, 40, 43, 44], "2u": 38, "2x": 36, "3": [2, 14, 39, 40, 41, 42, 43, 44], "30": [9, 10, 11, 14, 15, 36, 38, 39, 40, 41, 42, 43, 44], "32": [36, 38, 39, 40, 41, 42], "388": 4, "3d": 20, "3e": [36, 37, 38, 39], "4": [14, 36, 37, 38, 39, 40, 41, 42, 43, 44], "40": [36, 37, 38, 39, 43], "400": [36, 38, 39], "4x": 36, "4y": 36, "5": [14, 37, 38, 40, 41, 42, 43, 44], "50": [36, 37], "5000": [38, 39], "50000": 36, "6": [14, 36, 37, 38, 39, 40, 41, 42, 43, 44], "7": [40, 41, 42, 43, 44], "75": [36, 37, 38, 39], "8": [2, 37], "9": 2, "99": [36, 37, 38, 39], "A": [3, 13, 14, 16, 17, 19, 24, 25, 40, 41, 42, 43, 44, 45], "AND": 3, "AS": 3, "As": [36, 37, 38, 39, 40, 41, 42, 43, 44], "BE": 3, "BUT": 3, "FOR": 3, "For": [2, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45], "IN": 3, "If": [0, 1, 10, 13, 14, 15, 19, 36, 37, 38, 39], "In": [36, 37, 38, 39, 40, 41, 42, 43, 44], "It": [2, 7, 8, 12, 14, 17, 19, 21, 24, 36, 37, 38, 39, 40, 41, 42, 43, 44], "NO": 3, "NOT": 3, "No": 4, "Not": [16, 17], "OF": 3, "OR": 3, "On": 2, "Such": 12, "THE": 3, "TO": 3, "The": [2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 13, 14, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 31, 32, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45], "Then": [36, 37, 38, 39], "There": 9, "These": [40, 41, 42, 43, 44], "To": [2, 36, 37, 38, 39, 43, 44], "WITH": 3, "Will": [40, 41, 42, 43, 44], "With": [10, 15], "ab": [26, 27, 28, 29, 30, 31, 36, 37, 38, 39], "abil": 45, "about": [6, 14, 19, 36, 37, 38, 39, 40, 41, 42, 43, 44], "abov": [3, 36, 37, 38, 39, 43, 44], "absolut": 32, "abstract": [6, 7, 16, 18, 19, 20, 35], "acceler": [0, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45], "accept": [7, 8], "acknowledg": 4, "action": [2, 3], "activ": [2, 22, 23, 24, 25, 36, 37, 38, 39, 40, 41, 42, 43, 44], "actual": [7, 8, 9, 11, 12, 14, 18, 19, 33, 40, 41, 42, 43, 44], "actual_dirichlet": [7, 8], "actual_valu": 33, "ad": [32, 33, 40, 41, 42, 43, 44], "add": [1, 40], "addit": [36, 37, 38, 39], "affin": [6, 9, 11, 35], "after": [14, 19, 22, 24, 36, 37, 38, 39], "al": [10, 15], "all": [1, 3, 6, 7, 8, 14, 16, 19, 22, 24, 35, 40, 41, 42, 43, 44], "allow": [1, 21], "along": [43, 44], "also": [1, 14, 19, 21], "an": [1, 3, 10, 12, 13, 14, 15, 19, 24, 25, 36, 37, 38, 39, 41, 42, 44, 45], "analyt": [14, 19], "anandh": [0, 3, 4, 9, 10, 11, 14, 15, 16, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33], "anandh2024fastvpinn": 0, "ani": [3, 36, 37, 38, 39], "anyth": 9, "append": [36, 37, 38, 39], "appli": [24, 40], "apply_hard_boundary_constraint": 40, "appropri": 12, "approx": 32, "approxim": [32, 40, 41, 42, 43, 44], "apt": 2, "ar": [1, 4, 5, 6, 7, 8, 9, 10, 11, 12, 14, 15, 17, 19, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45], "architectur": [6, 22, 23, 24, 25, 36, 37, 38, 39], "archiv": [36, 37, 38, 39], "archiveprefix": 0, "area": 21, "area_averaged_cell_loss_list": 21, "arg": [22, 23, 24, 25], "argument": [40, 41, 42, 43, 44], "argv": [36, 37, 38, 39], "aris": 3, "arrai": [7, 8, 12, 14, 19, 32, 33, 36, 37, 38, 39], "array_lik": [10, 15], "arxiv": [0, 26, 27, 28, 29, 30, 31, 45], "assembl": 6, "assess": [43, 44], "assign": [1, 12, 13, 14, 19, 40, 41, 42, 43, 44], "assign_basis_funct": [12, 13], "assign_basis_values_at_quadrature_point": 12, "assign_fe_transform": [12, 13], "assign_forcing_term": 12, "assign_quad_weights_and_jacobian": 12, "assign_quadratur": 12, "assign_quadrature_coordin": 12, "assign_quadrature_rul": 13, "associ": [3, 14, 19], "attent": [22, 23, 24, 25, 36, 38, 39, 41, 42], "attnent": [40, 43, 44], "attribut": [12, 14, 19], "aug": [9, 10, 11, 14, 15], "author": [0, 3, 4, 9, 10, 11, 14, 15, 16, 17, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33], "avail": [10, 15, 40, 41, 42, 43, 44], "averag": 21, "avoid": 1, "axi": 33, "b": [10, 15, 36, 37], "b1": 44, "b2": 44, "b_x": [36, 37, 38, 44], "b_y": [36, 37, 38, 44], "back": [40, 41, 42, 43, 44], "backward": [12, 36, 37, 38, 39], "bangalor": 4, "bar": [36, 37, 38, 39, 40, 41, 42, 43, 44], "bar_format": [36, 37, 38, 39], "base": [7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 40, 41, 42, 43, 44, 45], "basi": [6, 10, 12, 13, 14, 15, 19, 35, 36, 37, 38, 39], "basic": [22, 24, 25], "basis2dqnjacobi": [10, 15], "basis_at_quad": 12, "basis_gradx_at_quad": 12, "basis_gradxx_at_quad": 12, "basis_gradxy_at_quad": 12, "basis_grady_at_quad": 12, "basis_grady_at_quad_ref": [14, 19], "basis_gradyy_at_quad": 12, "basisfunction2d": [10, 12, 13, 15], "batch_start_tim": [36, 37, 38, 39, 40, 41, 42, 43, 44], "bd_sampling_method": [20, 21, 44], "befor": [1, 36, 37, 38, 39, 40, 41, 42, 43, 44], "begin": [40, 41, 42, 43, 44], "being": [37, 38, 39, 40, 41, 42, 43, 44], "below": [6, 36, 37, 38, 39, 40, 41, 42, 43, 44], "best": [40, 41, 42, 43, 44], "beta": [22, 23, 24, 25, 36, 37, 38, 39, 40, 41, 42, 43, 44], "between": [32, 36, 37, 38, 39, 40, 41, 42, 43, 44], "bilinear": [6, 7, 8, 11, 22, 23, 25, 26, 27, 28, 29, 31, 35], "bilinear_param": [26, 28, 29, 30, 31], "bilinear_params_dict": [7, 8, 22, 23, 24, 25, 27, 31, 36, 37, 38, 39, 40, 41, 42, 43, 44], "bin": 2, "black": 1, "bold": [36, 37, 38, 39], "bool": [14, 19, 22, 23, 24, 25], "both": [17, 36, 37, 38, 39], "bottom": [40, 41, 42], "bottom_boundari": 43, "bound_condition_dict": [14, 19, 36, 37, 38, 39, 40, 41, 42, 43, 44], "bound_function_dict": [14, 19, 36, 37, 38, 39, 40, 41, 42, 43, 44], "boundari": [7, 8, 14, 19, 20, 21, 23, 45], "boundary_point": [14, 19, 36, 37, 38, 39, 40, 41, 42, 43, 44], "boundary_point_refinement_level": [20, 21, 44], "boundary_refinement_level": [36, 37, 38, 39, 44], "boundary_sampling_method": [36, 37, 38, 39], "bounndari": [36, 37, 38, 39], "box": 24, "branch": 1, "broadli": 6, "build": 2, "build_releas": 1, "c": [0, 3, 9, 11, 36, 37, 38, 44], "c_": [36, 37, 38, 39], "calcul": [6, 9, 11, 12, 17, 18, 26, 27, 28, 29, 30, 31, 38, 39, 40, 41, 42, 43, 44], "call": [22, 23, 24, 25, 40], "callabl": 12, "can": [2, 7, 8, 36, 37, 38, 39, 40, 41, 42, 43, 44], "captur": 45, "carri": [40, 41, 42, 43, 44], "case": [1, 36, 37, 38, 39, 44], "cast": 40, "caus": 2, "cd": 2, "cd2d": [27, 28, 36, 37, 38, 39], "cd2d_gear": [36, 37, 38, 39], "cd2d_inverse_circle_exampl": 44, "cd2d_inverse_domain": 44, "cdot": [36, 37, 38, 39], "cell": [7, 8, 9, 11, 12, 13, 14, 18, 19, 21, 36, 37, 38, 39, 40, 41, 42, 43, 44], "cell_coordin": [12, 13], "cell_index": [14, 19], "cell_residu": 21, "cell_typ": [12, 13, 14, 19, 36, 37, 38, 39, 40, 41, 42, 43, 44], "cells_list": 21, "center": [36, 37, 38, 39, 44], "centr": 4, "chang": [1, 40, 41, 42, 43, 44], "changelog": [9, 10, 11, 14, 15, 16, 17, 19, 22, 23, 24, 25, 32, 33], "charg": 3, "check": [1, 36, 38, 39], "ci": 2, "circl": 5, "circle_boundari": [36, 37, 38, 39, 44], "circle_quad": [36, 37, 38, 39], "circular": 44, "circular_quad": 44, "circular_quad_mesh": 44, "cite": 45, "claim": 3, "class": [6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44], "classifi": 6, "clone": 2, "cmgcd": 2, "co": [36, 37, 38, 41, 43, 44], "co_ordin": [9, 11], "code": [1, 2, 12, 40, 41, 42, 43, 44], "coeffici": [35, 39], "col_1_valu": 34, "col_2_valu": 34, "colour": [36, 37, 38, 39], "column": 34, "com": [2, 10, 15], "command": [2, 36, 37, 38, 39], "comment": 1, "commit": 1, "compat": [2, 12, 36, 37, 38, 39], "complex": [0, 14, 19, 36, 37, 38, 39, 40, 41, 42, 43, 45], "compon": [10, 14, 15, 36, 37, 38, 39, 40, 41, 42, 43, 44], "comput": [1, 6, 7, 8, 10, 12, 14, 15, 19, 23, 32, 35, 45], "compute_errors_combin": [32, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44], "compute_l1_error": [32, 35], "compute_l1_error_rel": [32, 35], "compute_l2_error": [32, 35], "compute_l2_error_rel": [32, 35], "compute_linf_error": [32, 35], "compute_linf_error_rel": [32, 35], "compute_util": [36, 37, 38, 39, 40, 41, 42, 43, 44], "conda": 2, "condit": [3, 14, 19], "config": [36, 37, 38, 39, 40, 41, 42, 43, 44], "configur": [22, 23, 24, 25], "connect": 3, "consid": 42, "consol": [6, 34, 36, 37, 38, 39, 40, 41, 42, 43, 44], "constant": [5, 24, 25, 27, 31, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45], "constraint": [6, 23, 35, 45], "contain": [5, 6, 10, 13, 14, 15, 16, 17, 19, 20, 21, 22, 23, 24, 25, 27, 31, 32, 33, 36, 37, 38, 39, 40, 41, 42, 43, 44], "contour": 33, "contract": 3, "contraint": 40, "contribut": 45, "control": 44, "convect": [5, 6, 35, 43, 44], "convent": 45, "converg": [43, 44], "convers": [7, 8], "convert": [7, 8, 36, 37, 38, 39], "coordin": [7, 8, 9, 10, 11, 12, 13, 14, 15, 18, 19, 36, 38, 39], "copi": [3, 14, 19, 36, 37, 38, 39], "copyright": 3, "correct": [43, 44], "correspond": [1, 11, 14, 18, 19, 40, 41, 42, 43, 44], "cover": 6, "coverag": 1, "creat": [1, 2, 14, 19, 23, 32, 33, 36, 37, 38, 39, 44], "csv": [37, 38, 39], "cu": [36, 37], "current": [2, 4, 12, 14, 19, 24, 36, 37, 38, 39, 40, 41, 42, 43, 44], "curv": 21, "custom": [7, 8, 23], "d": [9, 10, 11, 14, 15, 16, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33], "damag": 3, "data": [14, 19, 21, 23, 24, 25, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45], "data_nam": [21, 36, 37, 38, 39], "datahandl": [6, 8, 35, 40, 41, 42, 43, 44], "datahandler2d": [6, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44], "datatyp": [40, 41, 42, 43, 44], "date": [20, 21, 23, 26, 27, 28, 29, 30, 31, 32, 33], "ddtest_fcn": [10, 15], "deal": 3, "decai": [36, 37, 38, 39, 40, 41, 42, 43, 44], "decay_r": [36, 37, 38, 39], "decay_step": [36, 37, 38, 39], "decid": 44, "decomposit": [10, 15], "deep": 45, "def": [36, 37, 38, 39, 40, 41, 42, 43, 44], "default": [7, 8, 14, 19, 21, 22, 24, 25, 33], "defin": [6, 9, 10, 11, 15, 16, 17, 20, 21, 22, 23, 24, 25, 32], "degre": [10, 13, 14, 15, 19], "delimit": 37, "delta": [40, 41, 42, 43], "demonstr": [36, 37, 38, 39], "denot": [40, 41, 42, 43, 44], "dens": [6, 22, 24, 25, 35, 36, 37, 38, 39], "densemodel": [22, 23, 36, 37, 38, 39, 41, 42], "densemodel_hard": [23, 40], "densemodel_invers": [24, 43], "densemodel_inverse_domain": [25, 44], "depend": [2, 9, 10, 11, 14, 15, 16, 17, 19, 22, 24, 25, 36, 38, 39, 44], "deriv": [7, 8, 9, 10, 11, 15], "desc": [36, 37, 38, 39], "descript": [9, 10, 11, 14, 15, 16, 17, 19, 22, 23, 24, 25, 32, 33], "design": [43, 44], "detail": [2, 14, 19, 36, 37, 38, 39, 45], "develop": [4, 40, 41, 42, 43, 44], "dict": [7, 8, 14, 19, 21, 22, 23, 24, 25, 27, 31], "dictionari": [7, 8, 14, 19, 21, 22, 23, 24, 25, 27, 31, 36, 37, 38, 39, 40, 41, 42, 43, 44], "differ": 21, "differenti": 5, "diffus": [5, 6, 35, 39, 40, 41, 42, 44], "dimens": [14, 22, 24, 25, 40, 41, 42, 43, 44], "dimension": [40, 41, 42, 43, 44], "direct": [9, 21, 36, 37, 38, 39, 40, 41, 42, 43, 44], "directori": [36, 37, 38, 39], "dirichlet": [7, 8, 14, 19, 36, 37, 38, 39, 40, 43, 44], "distribut": [2, 3], "divid": [6, 40, 41, 42, 43, 44], "divij": [0, 3, 4, 23], "djacobi": [10, 15], "do": 3, "document": [1, 3, 35], "doe": [9, 37, 40], "dof": [14, 19], "domain": [6, 7, 8, 10, 14, 15, 19, 20, 21, 24, 25, 28, 29, 40, 41, 42, 43], "domain2d": [7, 8], "driven": [0, 36, 37, 38, 39, 40, 41, 42, 43, 44], "dtest_fcn": [10, 15], "dtype": [7, 8, 22, 23, 24, 25, 36, 37, 38, 39, 40, 41, 42, 43, 44], "due": 2, "duplic": 1, "dure": [10, 15], "e": [2, 36, 37, 38, 39, 43], "each": [6, 7, 8, 14, 19, 21, 23, 36, 37, 38, 39, 40, 41, 42, 43, 44], "edg": [36, 37, 38, 39], "effect": 44, "effici": [26, 27, 28, 29, 30, 31], "ehsan": [10, 15], "ehsankharazmi": [10, 15], "either": [6, 7, 8, 36, 37, 38, 39], "elaps": [36, 37, 38, 39], "element": [9, 10, 11, 14, 15, 16, 17, 18, 19, 35], "elif": [36, 37, 38, 39], "els": [36, 37, 38, 39], "enabl": [40, 41, 42, 43, 44], "end": [36, 37, 38, 39], "enforc": [23, 43], "enhanc": 45, "ensur": [14, 19], "entir": [14, 19, 25], "environ": 45, "ep": [36, 37, 38, 39, 40, 41, 42, 43, 44], "epoc": [36, 37, 38, 39], "epoch": [21, 33, 36, 37, 38, 39, 40, 41, 42, 43, 44], "eprint": 0, "epsilon": [36, 37, 38, 39, 40, 41, 42, 43, 44], "epsilon_": [43, 44], "equat": [5, 6, 26, 27, 28, 29, 30, 31, 36, 37, 38, 39, 41, 43, 44], "error": [10, 15, 32, 36, 37, 38, 39, 40, 41, 42, 43, 44], "estim": [40, 41, 42], "et": [10, 15], "eta": [9, 10, 11, 12, 13, 15, 16, 17, 18], "etc": [12, 36, 37, 38, 39, 43], "evalu": [10, 14, 15, 19], "event": 3, "everi": [36, 37, 38, 39], "exact": [7, 8, 14, 19, 32, 40, 41, 42, 43, 44], "exact_db": 37, "exact_sol": [7, 8, 14, 19], "exact_solut": [14, 19, 36, 37, 38, 39], "exact_solution_file_nam": [36, 37, 38, 39], "exact_solution_gener": [36, 37, 38, 39], "exampl": [7, 8, 14], "except": [10, 15], "exclus": 44, "execut": [36, 37, 38, 39], "exit": [36, 37, 38, 39], "exp": 43, "experi": [40, 41, 42, 43, 44], "experiment": [40, 41, 42, 43, 44], "explain": [40, 41, 42, 43, 44], "express": 3, "extern": [6, 7, 8, 14, 19, 20, 21, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45], "external_mesh_param": [36, 37, 38, 39, 40, 41, 42, 43, 44], "extract": [20, 21, 36, 37, 38, 39], "f": [36, 37, 38, 39, 40, 41, 42, 43, 44], "f_temp": [36, 37, 38, 39, 40, 41, 42], "factor": [22, 23, 24, 25], "fals": [14, 19, 22, 24, 25, 36, 37, 38, 39, 40, 41, 42, 43, 44], "faster": [7, 8], "fastvpinn": 2, "fe": [35, 36, 37, 38, 39, 45], "fe2d": 13, "fe2d_cel": [14, 19], "fe2dcel": [6, 35], "fe2dsetupmain": [6, 13, 35], "fe_cel": [14, 19], "fe_ord": [12, 13, 14, 19, 36, 37, 38, 39, 40, 41, 42, 43, 44], "fe_transformation_typ": [12, 13, 14, 19, 36, 37, 38, 39, 40, 41, 42, 43, 44], "fe_typ": [12, 13, 14, 19, 36, 37, 38, 39, 40, 41, 42, 43, 44], "featur": [1, 40, 41, 42, 43, 44], "fem": [37, 38, 39], "fem_output_gear_forward_sin": 37, "fespac": [7, 8, 12, 14, 40, 41, 42, 43, 44], "fespace2d": [6, 7, 8, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44], "fetransforamtion2d": [9, 11, 13, 18], "figur": [40, 41, 42], "file": [1, 3, 6, 7, 8, 9, 10, 11, 14, 15, 16, 17, 19, 20, 21, 22, 23, 24, 25, 32, 33], "file_nam": [7, 8, 14, 19], "file_prefix": 33, "filenam": [21, 32, 33, 36, 37, 38, 39], "fileprefix": 33, "fill": [36, 37, 38, 39], "final": 12, "finit": [14, 18, 19, 35], "first": [10, 14, 15, 19], "fit": 3, "flag": [22, 23, 36, 37, 38, 39], "flatten": 12, "float": [9, 10, 11, 15, 18, 32, 33, 36, 37, 38, 39], "float32": [7, 8, 36, 37, 38, 39, 40, 41, 42, 43, 44], "float64": [7, 8, 36, 37, 38, 39, 40, 41, 42, 43, 44], "focu": [22, 24, 25], "focus": [24, 25], "folder": [21, 36, 37, 38, 39, 40, 41, 42, 43, 44], "follow": [0, 1, 2, 3, 5, 36, 37, 38, 39, 40, 41, 42, 43, 44], "forc": [7, 8, 12, 14, 19, 22, 23, 24, 25, 26, 27, 28, 29, 31, 36], "force_function_list": [22, 23, 24, 25, 36, 37, 38, 39, 40, 41, 42, 43, 44], "forcing_at_quad": [12, 14, 19], "forcing_funct": [12, 14, 19, 26, 27, 28, 29, 30, 31, 36, 37, 38, 39, 40, 41, 42, 43, 44], "forcing_function_list": [7, 8, 36, 37, 38, 39, 40, 41, 42, 43, 44], "forcing_valu": 14, "fork": 1, "form": [6, 26, 28, 29, 40, 45], "format": [1, 6, 36, 37, 38, 39], "formul": 36, "formula": [16, 17], "forward": [23, 35, 45], "found": [10, 15, 36, 37, 38, 39, 40, 41, 42], "frac": [32, 44], "framework": 45, "free": 3, "freedom": [14, 19], "frequenc": [40, 41, 42, 43, 44, 45], "from": [3, 6, 7, 8, 9, 10, 11, 12, 14, 15, 18, 19, 20, 21, 23, 40, 41, 42, 43, 44, 45], "function": [7, 8, 10, 12, 13, 14, 15, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 45], "fund": [4, 45], "furnish": 3, "further": [36, 37, 38, 39], "ganesan": [0, 3, 4, 23], "gauss": [17, 36, 37, 38, 39], "gear": [5, 37], "gener": [6, 7, 8, 14, 19, 20, 21, 36, 37, 38, 39, 40, 41, 42, 43, 44], "generate_dirichlet_boundary_data": [14, 19], "generate_dirichlet_boundary_data_vector": 14, "generate_mesh_plot": [14, 19, 36, 37, 38, 39], "generate_plot": 14, "generate_quad_mesh_intern": [21, 40, 41, 42, 43], "generate_vtk_for_test": [20, 21], "geometr": [40, 41, 42, 43, 44], "geometri": [0, 35, 45], "geometry2d": [6, 35, 40, 41, 42], "geometry_2d": [35, 36, 37, 38, 39], "get": [1, 2, 7, 8, 14, 19, 22, 23, 25, 36, 37, 38, 39, 43], "get_bilinear_params_dict": [36, 37, 38, 39, 40, 41, 42, 43, 44], "get_bilinear_params_dict_as_tensor": [7, 8], "get_bound_cond_dict": [36, 37, 38, 39, 40, 41, 42, 43, 44], "get_boundary_function_dict": [36, 37, 38, 39, 40, 41, 42, 43, 44], "get_config": [22, 23, 24, 25], "get_dirichlet_input": [7, 8], "get_forcing_function_valu": [14, 19], "get_forcing_function_values_vector": 14, "get_inverse_param": [7, 8], "get_inverse_params_actual_dict": [43, 44], "get_jacobian": [9, 11, 18], "get_num_quad_point": [16, 17], "get_orig_from_ref_deriv": [9, 11], "get_orig_from_ref_second_deriv": [9, 11], "get_original_from_ref": [9, 11, 18], "get_quad_valu": [16, 17], "get_quadrature_actual_coordin": [14, 19], "get_quadrature_weight": 14, "get_sensor_data": [7, 8, 14, 19], "get_sensor_data_extern": [14, 19], "get_shape_function_grad_i": [14, 19], "get_shape_function_grad_x": [14, 19], "get_shape_function_grad_x_ref": [14, 19], "get_shape_function_grad_y_ref": [14, 19], "get_shape_function_v": [14, 19], "get_test_point": [7, 8, 20, 21, 36, 38, 39], "ghose": [0, 3, 4, 23], "git": 2, "github": [2, 10, 15, 36, 37, 38, 39, 40, 41, 42], "given": [6, 7, 8, 10, 11, 12, 13, 14, 15, 18, 19, 20, 21, 36, 37, 38, 39, 40, 41, 42, 43, 44], "glx": 2, "gmsh": [2, 6, 20, 21, 36, 37, 38, 39, 44], "govern": 6, "gpu": [36, 38, 39, 40, 41, 42, 43, 44], "grad_x_mat_list": [7, 8, 36, 37, 38, 39, 40, 41, 42, 43, 44], "grad_xx_ref": [9, 11], "grad_xy_ref": [9, 11], "grad_y_mat_list": [7, 8, 36, 37, 38, 39, 40, 41, 42, 43, 44], "grad_yy_ref": [9, 11], "gradi": [10, 15], "gradient": [9, 11, 12, 14, 19, 26, 27, 28, 29, 31], "gradx": [10, 15], "gradxi": [10, 15], "gradxx": [10, 15], "gradyi": [10, 15], "grant": [3, 4], "greater": [14, 19], "green": [36, 37, 38, 39], "growth": [36, 38, 39, 40, 41, 42, 43, 44], "guess": [43, 44], "guidelin": 1, "h": 45, "ha": [36, 37, 38, 39, 43, 44, 45], "handl": [6, 7, 8, 36, 37, 38, 39, 45], "hard": [6, 23, 35, 45], "hard_constraint_funct": 40, "hardcod": [40, 41, 42], "have": [36, 37, 38, 39, 44], "header": 37, "helmholtz": [5, 6, 29, 35, 39], "helmholtz2d": [38, 39, 41], "helmholtz_exampl": 41, "help": 1, "helper": 6, "henc": [40, 41, 42, 43, 44], "here": [1, 36, 37, 38, 39, 40, 41, 42, 43, 44], "herebi": 3, "hessian": [22, 23, 24, 25, 36, 37, 38, 39, 40, 41, 42, 43, 44], "hidden": [40, 41, 42, 43, 44], "higher": 45, "highli": 45, "himanshu": 0, "histori": [26, 27, 28, 29, 30, 31], "hold": [6, 14], "holder": 3, "host": [22, 23, 24, 25, 36, 37, 38, 39], "how": [36, 37, 38, 39, 40, 42, 43, 44], "hp": [10, 15, 45], "http": [2, 10, 15, 26, 27, 28, 29, 30, 31], "i": [2, 3, 4, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45], "i_": [36, 37, 38, 39], "i_activ": [36, 37, 38, 39, 40, 41, 42, 43, 44], "i_beta": [36, 37, 38, 39], "i_boundary_refinement_level": [36, 37, 38, 39, 44], "i_boundary_sampling_method": [36, 37, 38, 39, 44], "i_dtyp": [36, 37, 38, 39, 40, 41, 42, 43, 44], "i_epoch": [36, 37, 38, 39], "i_exact_solution_file_nam": [36, 37, 38, 39], "i_exact_solution_gener": [36, 37, 38, 39], "i_fe_ord": [36, 37, 38, 39, 40, 41, 42, 43, 44], "i_fe_typ": [36, 37, 38, 39, 40, 41, 42, 43, 44], "i_generate_mesh_plot": [36, 37, 38, 39], "i_learning_rate_dict": [36, 37, 38, 39, 40, 41, 42, 43, 44], "i_mesh_file_nam": [36, 37, 38, 39, 44], "i_mesh_generation_method": [36, 37, 38, 39, 40, 41, 42, 43, 44], "i_mesh_typ": [36, 37, 38, 39, 40, 41, 42, 43, 44], "i_model_architectur": [36, 37, 38, 39, 43, 44], "i_n_boundary_point": [36, 37, 38, 39, 40, 41, 42, 43], "i_n_cells_i": [36, 37, 38, 39, 40, 41, 42, 43], "i_n_cells_x": [36, 37, 38, 39, 40, 41, 42, 43], "i_n_test_points_i": [36, 37, 38, 39, 40, 41, 42, 43, 44], "i_n_test_points_x": [36, 37, 38, 39, 40, 41, 42, 43, 44], "i_output_path": [36, 37, 38, 39, 40, 41, 42, 43, 44], "i_quad_ord": [36, 37, 38, 39, 40, 41, 42, 43, 44], "i_quad_typ": [36, 37, 38, 39, 40, 41, 42, 43, 44], "i_set_memory_growth": [36, 37, 38, 39], "i_update_console_output": [36, 37, 38, 39], "i_use_attent": [36, 37, 38, 39, 40, 41, 42, 43, 44], "i_x_max": [36, 37, 38, 39, 40, 41, 42, 43], "i_x_min": [36, 37, 38, 39, 40, 41, 42, 43], "i_y_max": [36, 37, 38, 39, 40, 41, 42, 43], "i_y_min": [36, 37, 38, 39, 40, 41, 42, 43], "id": [36, 37, 38, 39, 40, 41, 42, 44], "identifi": [43, 44], "ignor": [40, 41, 42, 43, 44], "iloc": 37, "imag": [40, 41, 42, 43, 44], "immut": [14, 19], "implement": [9, 11, 14, 19, 22, 24, 25, 26, 27, 28, 29, 30, 31, 43, 44, 45], "implemnt": [26, 27, 28, 29, 30, 31], "impli": 3, "importerror": [10, 15], "includ": [1, 3, 40, 41, 42, 43, 44], "indent": 1, "index": [14, 19, 45], "india": 4, "indian": 4, "indic": [14, 19, 36, 37, 38, 39], "infer": [10, 15, 40, 41, 42, 43, 44], "inform": [6, 10, 14, 15, 19, 21, 22, 24, 25, 40, 41, 42, 43, 44], "inherit": 23, "inhous": 37, "initi": [9, 10, 11, 14, 15, 19, 22, 24, 25, 26, 27, 28, 29, 30, 31, 36, 37, 38, 39, 43, 44, 45], "initial_learning_r": [36, 37, 38, 39, 40, 41, 42, 43, 44], "initialis": [36, 37, 38, 39], "inner": 37, "inner_boundari": 37, "input": [7, 8, 12, 22, 23, 24, 25], "input_dirichlet": [7, 8], "input_invers": [40, 43], "input_inverse_domain": 44, "input_tensors_list": [22, 23, 24, 25, 36, 37, 38, 39, 40, 41, 42, 43, 44], "instal": [1, 45], "instanc": [12, 13, 14, 19], "instanti": 44, "instead": 40, "institut": 4, "int": [7, 8, 10, 12, 13, 14, 15, 16, 17, 19, 20, 21, 22, 25, 36, 37, 38, 39], "integ": 23, "integr": [14, 19], "intermedi": 11, "intern": [6, 20, 21, 36, 37, 38, 39, 40, 41, 42, 43, 44], "internal_mesh_param": [36, 37, 38, 39, 40, 41, 42, 43, 44], "interv": [40, 41, 42, 43, 44], "introduc": [40, 41, 42, 43, 44], "invalid": 13, "invers": [7, 8, 14, 19, 24, 25, 27, 28, 29, 31, 33, 35, 40, 45], "inverse_eps_predict": 43, "inverse_param_dict": [27, 31], "inverse_param_nam": 33, "inverse_params_dict": [24, 25, 31, 43], "inverse_params_dict_funct": [7, 8], "inverse_params_list": 28, "inverse_predict": 33, "inverse_uniform": 43, "iqr": [36, 37, 38, 39], "issu": [1, 2, 23], "iter": [40, 41, 42, 43, 44], "its": [6, 40, 41, 42, 43, 44], "j": [36, 37, 38, 39], "j_": [36, 37, 38, 39], "jacobi": [6, 10, 15, 17, 35, 36, 37, 38, 39], "jacobi_wrapp": [10, 15], "jacobian": [9, 11, 12, 14, 18, 19], "jain": 0, "just": 2, "k": [10, 15, 38, 41], "kei": [36, 37, 38, 39, 40, 41, 42, 43, 44], "kera": [23, 24, 25, 36, 37, 38, 39], "kharazmi": [10, 15, 45], "kind": 3, "known": [23, 43, 44], "known_issu": [9, 10, 11, 14, 15, 16, 17, 19, 22, 24, 25, 32, 33], "kwarg": [22, 23, 24, 25], "l1": [32, 36, 37, 38, 39], "l1_error": [36, 37, 38, 39], "l1_error_rel": [36, 37, 38, 39], "l2": [32, 36, 37, 38, 39], "l2_error": [36, 37, 38, 39], "l2_error_rel": [36, 37, 38, 39], "l_bar": [36, 37, 38, 39], "l_inf": 32, "lab": 4, "label": 33, "last": [36, 37, 38, 39], "latest": 2, "layer": [22, 23, 24, 25, 36, 37, 38, 39, 40, 41, 42, 43, 44], "layer_dim": [22, 23, 24, 25, 36, 37, 38, 39, 40, 41, 42, 43, 44], "learn": [22, 23, 24, 25, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45], "learning_r": [36, 37, 38, 39, 40, 41, 42, 43, 44], "learning_rate_dict": [22, 23, 24, 25, 36, 37, 38, 39, 40, 41, 42, 43, 44], "left": [40, 41, 42, 44], "left_boundari": 43, "legend": 33, "legend_label": 33, "legendr": [17, 36, 37, 38, 39], "len": [36, 37, 38, 39], "level": [20, 36, 38, 39], "lg": 0, "lh": [36, 38, 39], "liabil": 3, "liabl": 3, "libgl": 2, "libgl1": 2, "librari": [1, 5], "licens": 45, "like": [4, 14, 19, 36, 37, 38, 39, 40, 41, 42, 43, 44], "limit": [3, 21, 40, 41, 42, 43], "linf": [36, 37, 38, 39], "linf_error": [36, 37, 38, 39], "linf_error_rel": [36, 37, 38, 39], "lint": 1, "list": [7, 8, 13, 21, 22, 23, 24, 25, 26, 28, 29, 33, 34], "load": [40, 41, 42, 43, 44], "local": 1, "log": 33, "loop": [14, 19, 22, 23, 24, 25], "loss": [6, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 33, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45], "loss_": [36, 37, 38, 39], "loss_arrai": [36, 37, 38, 39], "loss_dirichlet": [36, 37, 38, 39], "loss_funct": [22, 23, 24, 25, 33, 36, 37, 38, 39, 40, 41, 42, 43, 44], "loss_function_list": 33, "loss_pd": [36, 37, 38, 39], "lower": 21, "m": 2, "mac": 2, "maco": 2, "made": 1, "mai": [19, 20], "main": [1, 6, 14], "main_cd2d_gear": 37, "main_helmholtz": 41, "main_helmholtz_hard": 41, "main_invers": 43, "main_inverse_domain_circl": 44, "main_poisson2d": 42, "main_poisson2d_hard": [40, 42], "maintain": [7, 8, 36, 37, 38, 39], "make": [40, 41, 42, 43, 44], "manag": [40, 41, 42, 43, 44], "mani": 44, "map": [43, 44], "math": 32, "mathbf": [36, 37], "matplotlib": 2, "matric": [14, 19, 22, 23, 24, 25], "matrix": [18, 22, 26, 27, 28, 29, 31], "matter": 37, "max_": 32, "maximum": [36, 38, 39], "mean": [36, 37, 38, 39], "mechan": [24, 25, 36, 38, 39], "median": [36, 37, 38, 39], "memori": [36, 38, 39, 40, 41, 42, 43, 44], "mention": [36, 37, 38, 39], "merchant": 3, "merg": 3, "mesa": 2, "mesh": [6, 7, 8, 13, 14, 19, 20, 21, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45], "mesh_fil": [20, 21, 36, 37, 38, 39, 44], "mesh_file_nam": [36, 37, 38, 39, 44], "mesh_generation_method": [20, 21, 36, 37, 38, 39, 40, 41, 42, 43, 44], "mesh_typ": [7, 8, 20, 21, 36, 37, 38, 39, 40, 41, 42, 43, 44], "messag": 1, "method": [9, 10, 11, 12, 14, 15, 18, 19, 20, 21, 22, 23, 24, 25, 30, 36, 37, 38, 39], "methodologi": [14, 19], "metric": [43, 44], "mhrd": 4, "minimum": [36, 38, 39], "misc": 0, "mit": 3, "mix": 11, "mode": 23, "model": [35, 45], "model_architectur": [36, 37, 38, 39, 40, 41, 42, 43, 44], "model_hard": 40, "model_invers": 43, "model_inverse_domain": 44, "model_weight": [36, 37, 38, 39], "modelimport": [41, 42], "modifi": 3, "modul": [35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45], "more": [2, 36, 37, 38, 39, 43, 45], "msh": 21, "mult": [12, 14], "multipl": 33, "multipli": [12, 36, 37, 38, 39, 40, 41, 42, 43, 44], "must": [40, 41, 42, 43, 44], "n": [2, 10, 15, 32, 36, 37, 38, 39], "n_basis_funct": 12, "n_boundary_point": [36, 37, 38, 39, 40, 41, 42, 43], "n_cells_i": [21, 36, 37, 38, 39, 40, 41, 42, 43], "n_cells_x": [21, 36, 37, 38, 39, 40, 41, 42, 43], "n_quad_point": [12, 14], "n_shape_funct": 12, "n_test": [10, 15], "n_test_points_i": [21, 36, 37, 38, 39, 40, 41, 42, 43], "n_test_points_x": [21, 36, 37, 38, 39, 40, 41, 42, 43], "nabla": [36, 37, 38, 39], "name": [7, 8, 21, 33, 34, 36, 37, 38, 39], "ncol": [36, 37, 38, 39], "ndarrai": [9, 11, 12, 14, 18, 19, 20, 21, 32, 33], "necessari": [6, 14, 19, 24, 36, 37, 38, 39, 40, 41, 42], "need": [14, 36, 37, 38, 39, 40, 41, 42, 43, 44], "nepoch": [36, 37, 38, 39], "network": [6, 10, 15, 22, 23, 24, 25, 26, 27, 28, 29, 31, 36, 37, 38, 39, 40, 41, 42, 43, 44], "neural": [6, 10, 15, 22, 23, 24, 25, 26, 27, 28, 29, 31, 36, 37, 38, 39, 40, 41, 42, 43, 44], "neuron": [23, 40, 41, 42, 43, 44], "new": 1, "nn": [22, 24, 25, 44, 45], "none": [7, 8, 9, 10, 11, 12, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 32, 33, 34, 37], "noninfring": 3, "normal": 21, "note": [12, 14, 19, 36, 37, 38, 39, 45], "notic": 3, "now": [11, 36, 37, 38, 39, 40, 41, 42, 43, 44], "np": [7, 8, 14, 19, 36, 37, 38, 39, 40, 41, 42, 43, 44], "nth": [36, 37, 38, 39], "num_boundary_point": [21, 40, 41, 42, 43], "num_epoch": [36, 37, 38, 39, 40, 41, 42, 43, 44], "num_point": [14, 19], "num_quad_point": 16, "num_sensor_point": [7, 8, 43, 44], "num_shape_funct": [10, 15], "number": [7, 8, 10, 14, 15, 16, 17, 19, 21, 23, 36, 37, 38, 39, 40, 41, 42, 43, 44], "numpi": [7, 8, 9, 10, 11, 12, 14, 15, 16, 17, 18, 19, 20, 21, 32, 33, 36, 37, 38, 39], "object": [7, 8, 12, 13, 14, 16, 18, 19, 20], "obtain": [3, 6, 12, 14, 19, 36, 37, 38, 39, 40, 41, 42, 43, 44], "occur": [10, 15], "offici": 2, "often": [40, 41, 42, 43, 44], "old": 12, "omega": [36, 37, 38, 39, 40, 41, 42, 43], "omegai": [39, 40, 42], "omegax": [39, 40, 42], "onc": 43, "one": [24, 36, 37, 38, 39], "ones_lik": [37, 44], "onli": [6, 14, 19, 24, 36, 37, 38, 39, 40, 41, 42, 43, 44], "open": [1, 36, 37, 38, 39], "optimis": 45, "option": [7, 8, 14, 19, 21, 22, 25, 33], "order": [10, 12, 14, 15, 16, 17, 19, 36, 38, 39, 40, 41, 42, 43, 44], "org": [26, 27, 28, 29, 30, 31], "organ": 5, "orig_factor_matric": [22, 23, 24, 25, 36, 37, 38, 39, 40, 41, 42, 43, 44], "origin": [9, 11, 18, 22, 23, 24, 25], "other": [3, 36, 38, 39], "otherwis": 3, "our": [26, 27, 28, 29, 30, 31, 36, 37, 38, 39, 40, 41, 42, 43, 44], "out": [3, 24, 40, 41, 42, 43, 44], "outer": 37, "outer_boundari": 37, "output": [6, 14, 19, 21, 22, 23, 24, 25, 26, 27, 28, 29, 31, 40, 41, 42, 43, 44], "output_fold": 21, "output_path": [14, 19, 21, 33, 36, 37, 38, 39, 40, 41, 42, 43, 44], "over": [14, 19, 25], "own": 6, "p": 45, "packag": [2, 6, 36, 37, 38, 39], "page": [2, 5, 45], "panda": [36, 37, 38, 39], "paper": [0, 45], "param": [23, 32, 33, 34, 36, 37, 38, 39, 40], "paramet": [5, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 31, 32, 33, 45], "params_dict": [22, 23, 24, 25, 36, 37, 38, 39, 40, 41, 42, 43, 44], "parmoon": [9, 11, 37], "part": [36, 37, 38, 39], "partial": [4, 5, 36, 37, 38, 39, 44], "particular": [3, 43, 44], "pass": [14, 19, 23, 40, 41, 42, 43, 44], "path": [14, 19, 20, 21, 33, 36, 37, 38, 39], "pathlib": [36, 37, 38, 39], "pd": [36, 37, 38, 39], "pde": [5, 22, 26, 27, 28, 29, 30, 31, 45], "pde_loss_cd2d": [26, 27, 36, 37, 38, 39], "pde_loss_cd2d_inverse_domain": [28, 44], "pde_loss_helmholtz": [29, 38, 39, 41], "pde_loss_poisson": [30, 40, 42], "pde_loss_poisson_invers": [31, 43], "per": [36, 37, 38, 39], "percentil": [36, 37, 38, 39], "perform": [12, 43, 44], "permiss": 3, "permit": 3, "person": 3, "pertain": [40, 41, 42, 43, 44], "physic": [10, 15, 21, 22, 24, 25, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44], "pi": [38, 39, 40, 41, 42], "pinn": [22, 23, 24, 25, 45], "pip": 45, "pleas": [0, 1, 2, 45], "plot": [6, 14, 19, 21, 33, 35, 40, 41, 42, 43, 44], "plot_adaptive_mesh": 21, "plot_arrai": [33, 35], "plot_contour": [33, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44], "plot_inverse_param_funct": [33, 35], "plot_inverse_test_loss_funct": [33, 35], "plot_loss_funct": [33, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44], "plot_multiple_loss_funct": [33, 35], "plot_test_loss_funct": [33, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44], "plot_test_time_loss_funct": [33, 35], "plot_util": [36, 37, 38, 39, 40, 41, 42, 43, 44], "point": [6, 7, 8, 10, 12, 14, 15, 16, 17, 19, 20, 21, 36, 37, 38, 39, 40, 41, 42, 43, 44], "poission": [6, 35], "poisson": [5, 6, 30, 31, 35, 36, 37, 38, 40, 41, 43], "poisson2d": [39, 40, 41, 42], "poisson2d_invers": 43, "poisson_invers": 43, "polynomi": [10, 15, 36, 37, 38, 39, 40, 41, 42, 43, 44], "portion": 3, "pr": 1, "practic": [40, 41, 42, 43, 44], "pre": 1, "pred_grad_x_nn": [26, 27, 28, 29, 30, 31], "pred_grad_y_nn": [26, 27, 28, 29, 30, 31], "pred_nn": [26, 27, 28, 29, 30, 31], "predict": [6, 26, 27, 28, 29, 31, 32, 33, 36, 37, 38, 39, 40, 41, 43, 44], "prediction_": [36, 37, 38, 39], "prefix": [33, 36, 37, 38, 39], "present": [36, 37, 38, 39, 44], "primaryclass": 0, "print": [6, 14, 19, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44], "print_tabl": [34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44], "print_util": [36, 37, 38, 39, 40, 41, 42, 43, 44], "problem": [7, 8, 14, 19, 20, 21, 24, 25, 26, 27, 28, 29, 30, 31, 35, 36, 37, 38, 39], "process": 6, "prof": 4, "progress": [36, 37, 38, 39, 40, 41, 42, 43, 44], "progress_bar": [36, 37, 38, 39], "project": [1, 9, 11], "proper": 1, "provid": [2, 3, 6, 36, 37, 38, 39, 40, 41, 42, 43, 44], "publish": 3, "pull": 1, "purpos": [3, 6, 36, 37, 38, 39, 44], "py": [1, 9, 10, 11, 14, 15, 16, 17, 19, 20, 21, 22, 23, 24, 25, 32, 33, 40, 41, 42, 43, 44], "pytest": [36, 37, 38, 39], "python": [2, 36, 37, 38, 39], "python3": [2, 36, 37, 38, 39, 40, 41, 42, 43, 44], "q1": [10, 15], "qquad": 44, "quad": [9, 11, 36, 37, 38, 39, 40, 41, 42, 43, 44], "quad_actual_coordin": 12, "quad_eta": 12, "quad_ord": [12, 13, 14, 16, 17, 19, 36, 37, 38, 39, 40, 41, 42, 43, 44], "quad_typ": [12, 13, 14, 16, 17, 19, 36, 37, 38, 39, 40, 41, 42, 43, 44], "quad_xi": 12, "quadaffin": 9, "quadbilinear": 11, "quadratur": [7, 8, 12, 13, 14, 16, 17, 19, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44], "quadratureformula": 17, "quadrilater": [16, 17, 21, 36, 37, 38, 39, 40, 41, 42, 44], "question": [40, 41, 42, 43, 44], "r": [36, 37, 38, 39], "r_bar": [36, 37, 38, 39], "radiu": [36, 37, 38, 39, 44], "rais": [1, 10, 13, 14, 15, 19, 36, 37, 38, 39], "random": [14, 19], "rang": [36, 37, 38, 39, 40, 41, 42, 43, 44], "rate": [22, 23, 24, 25, 36, 37, 38, 39, 40, 41, 42, 43, 44], "reaction": [36, 44], "read": [20, 21], "read_csv": 37, "read_mesh": [20, 21, 36, 37, 38, 39, 44], "readi": [40, 41, 42, 43, 44], "recommend": 2, "recreat": 24, "red": [36, 37, 38, 39], "ref": 45, "ref_gradi": [9, 11], "ref_gradx": [9, 11], "refer": [1, 2, 9, 11, 14, 18, 19, 26, 27, 28, 29, 30, 31], "referenc": [9, 11], "refin": [20, 21, 36, 37, 38, 39, 44, 45], "refinement_level": [20, 21, 36, 37, 38, 39, 44], "regular": [40, 41, 42, 43], "rel": [32, 36, 37, 38, 39], "relat": [40, 41, 42, 43, 44], "replac": 44, "repositori": [1, 2, 36, 37, 38, 39, 40, 41, 42], "repres": [13, 14, 18, 19, 23], "request": 1, "requir": [2, 6, 10, 14, 15, 19, 40, 41, 42, 43, 44], "research": 0, "reshap": [36, 37, 38, 39], "residu": [21, 40], "respect": [7, 8, 9, 11, 14, 19, 37, 40, 41, 42, 43, 44], "respons": [6, 7, 8, 36, 37, 38, 39], "restrict": [3, 40, 41, 42, 43, 44], "result": [14, 19, 21, 36, 37, 38, 39, 40, 41, 42, 43, 44], "return": [7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 36, 37, 38, 39, 40, 41, 42, 43, 44], "rh": [14, 36, 37, 38, 39, 40, 41, 42, 43, 44], "rich": [36, 37, 38, 39], "right": [3, 40, 41, 42, 44], "right_boundari": 43, "robust": 45, "routin": [6, 19, 35], "rtype": [23, 32, 33, 34, 40], "rule": [12, 13, 36, 37, 38, 39, 40, 41, 42, 43, 44], "run": [1, 2, 40, 41, 42, 43, 44], "safe_load": [36, 37, 38, 39], "same": [7, 8, 36, 37, 38, 39], "sampl": [14, 19, 20, 36, 37, 38, 39, 44], "sashikumaar": [0, 3, 4, 23], "save": [14, 21, 33], "save_weight": [36, 37, 38, 39], "savetxt": [36, 37, 38, 39], "scalar": [21, 40, 41, 42, 43, 44], "scale": 33, "schedul": [36, 37, 38, 39, 40, 41, 42, 43, 44], "scienc": 4, "scipi": [10, 15, 16, 17], "score": 1, "search": 45, "second": [9, 10, 11, 14, 15, 19, 33, 36, 37, 38, 39], "section": [6, 36, 37, 38, 39, 40, 41, 42, 43, 44], "self": 12, "sell": 3, "sens": [43, 44], "sensor": [7, 8, 14, 19, 24, 25, 43, 44], "sensor_data_fil": 44, "sensor_list": [24, 25, 43, 44], "sensor_valu": [43, 44], "sep": [21, 22, 24, 25, 26, 27, 28, 29, 30, 31], "serial": 24, "set": [9, 11, 12, 18, 45], "set_cel": [9, 11, 18], "set_finite_el": [14, 19], "set_memory_growth": [36, 37, 38, 39, 40, 41, 42, 43, 44], "setup": [13, 35], "sever": 6, "shall": 3, "shape": [7, 8, 12, 14, 19, 26, 27, 28, 29, 31, 36, 37, 38, 39], "shape_val_mat_list": [7, 8, 36, 37, 38, 39, 40, 41, 42, 43, 44], "shell": 4, "should": [1, 21, 36, 37, 38, 39, 40, 41, 42, 43, 44], "shown": [40, 41, 42, 43, 44], "similarli": 43, "simpli": [2, 44], "simultan": [43, 44], "sin": [36, 37, 38, 39, 40, 41, 42, 43, 44], "sin_co": [40, 42], "sinc": [37, 40, 44], "singl": 1, "size": 12, "snippet": 43, "so": [3, 7, 8, 40, 41, 42, 43, 44], "softwar": [3, 36, 37, 38, 39], "sol": [36, 37, 38, 39], "solut": [7, 8, 14, 19, 21, 23, 32, 45], "solution_arrai": [36, 37, 38, 39], "solv": [5, 22, 23, 36, 37, 38, 39, 45], "solver": [40, 41, 42, 43, 44], "some": [1, 43, 44], "sourc": [7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 45], "space": [14, 19], "spade": 4, "spatial": [5, 35, 40, 43, 45], "special": [36, 37, 38, 39, 45], "specif": [14, 43, 44], "specifi": [9, 11, 14, 16, 17, 19, 21, 22, 24, 25, 36, 37, 38, 39, 40, 41, 42, 43, 44], "spur": 5, "sqrt": [32, 37], "squar": 5, "squash": 1, "staircas": [36, 37, 38, 39], "standard": 1, "star": 4, "start": [1, 43], "step": [22, 23, 25], "store": [12, 14, 19, 21, 37, 38, 39, 40, 41, 42, 43, 44], "str": [7, 8, 12, 13, 14, 16, 17, 19, 20, 21, 22, 23, 24, 25, 33, 34, 36, 37, 38, 39], "string": [40, 41, 42, 43, 44], "subclass": [24, 25], "subject": 3, "sublicens": 3, "subpackag": 6, "substanti": 3, "substitut": 36, "sudo": 2, "sum": [36, 37, 38, 39], "sum_": 32, "supervis": [4, 40], "support": [4, 6, 17, 21, 24, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45], "sy": [36, 37, 38, 39], "synthet": [43, 44], "system": 2, "tabl": [34, 36, 37, 38, 39], "tag": [36, 37, 38, 39, 44], "take": [12, 44], "taken": [36, 37, 38, 39], "tanh": [22, 24, 25, 36, 37, 38, 39, 40, 43], "task": 1, "team": 45, "technologi": 4, "tensor": [0, 6, 7, 8, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45], "tensor_dtyp": [22, 23, 24, 25, 36, 37, 38, 39, 40, 41, 42, 43, 44], "tensorflow": [7, 8, 22, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45], "term": 44, "term1": [38, 41], "term2": [38, 41], "term3": [38, 41], "term4": [38, 41], "test": [1, 2, 7, 8, 10, 15, 20, 21, 26, 27, 28, 29, 31, 33, 35, 36, 37, 38, 39, 40, 41, 42], "test_fcni": [10, 15], "test_fcnx": [10, 15], "test_grad_x_mat": [26, 27, 28, 29, 30, 31], "test_grad_y_mat": [26, 27, 28, 29, 30, 31], "test_loss_arrai": [36, 37, 38, 39], "test_point": [20, 21, 36, 37, 38, 39], "test_shape_val_mat": [26, 27, 28, 29, 30, 31], "text": [36, 37, 38, 39, 43, 44], "tf": [7, 8, 22, 23, 24, 25, 26, 27, 28, 29, 31, 36, 37, 38, 39, 40], "th": [10, 15], "than": [14, 19], "thank": [1, 4], "thei": 44, "them": [7, 8, 12, 43], "theori": 45, "thi": [1, 3, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45], "thivin": [0, 3, 4, 9, 10, 11, 14, 15, 16, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33], "those": [12, 14, 19, 40, 41, 42, 43, 44], "throughout": [40, 41, 42, 43, 44], "throw": [36, 37, 38, 39], "thu": [40, 41, 42, 43, 44], "time": [21, 33, 36, 37, 38, 39, 40, 41, 42, 43, 44], "time_arrai": [33, 36, 37, 38, 39], "time_per_epoch": [36, 37, 38, 39], "titl": [0, 33, 34], "toggl": [40, 41, 42, 43, 44], "top": [36, 37, 38, 39, 40, 41, 42], "top_boundari": 43, "tort": 3, "total": [14, 19, 36, 37, 38, 39, 40, 41, 42, 43, 44], "total_loss": [36, 37, 38, 39], "tqdm": [36, 37, 38, 39], "train": [6, 22, 23, 24, 25, 41, 42, 43, 44, 45], "train_dirichlet_input": [36, 37, 38, 39, 40, 41, 42, 43, 44], "train_dirichlet_output": [36, 37, 38, 39, 40, 41, 42, 43, 44], "train_step": [22, 23, 24, 25, 36, 37, 38, 39, 40, 41, 42, 43, 44], "transform": [9, 11, 12, 13, 14, 18, 19, 35], "true": [36, 37, 38, 39, 40, 41, 42, 43, 44], "tune": [43, 44], "tupl": [7, 8, 9, 13, 14, 16, 17, 18, 19, 21, 32], "tutori": 45, "two": [14, 19, 34], "txt": [36, 37, 38, 39], "type": [2, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44], "u": [1, 36, 37, 38, 39, 40, 41, 42, 43, 44], "u_": 32, "u_approx": 32, "u_exact": 32, "u_temp": 36, "ubuntu": 2, "under": [4, 40, 41, 42, 43, 44], "uniform": [36, 37, 38, 39, 40, 41, 42, 44, 45], "unit": [5, 36, 37, 38, 39], "unknown": [10, 15, 43, 44], "up": 45, "updat": [1, 14, 19, 36, 40, 41, 42, 43, 44], "update_console_output": [36, 37, 38, 39], "update_progress_bar": 36, "update_solution_imag": 36, "upper": 21, "us": [0, 1, 2, 3, 5, 7, 8, 9, 10, 11, 12, 13, 14, 15, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 31, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45], "usag": [14, 36, 37, 38, 39, 40, 41, 42, 43, 44], "use_attent": [22, 23, 24, 25, 36, 37, 38, 39, 40, 41, 42, 43, 44], "use_lr_schedul": [36, 37, 38, 39, 40, 41, 42, 43, 44], "user": [2, 6, 36, 37, 38, 39, 44], "usual": [40, 41, 42, 43, 44], "util": [35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45], "val": [39, 43, 44], "valid": [36, 37, 38, 39], "valu": [7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 23, 26, 27, 28, 29, 31, 33, 34, 36, 37, 38, 39], "valueerror": [10, 13, 14, 15, 19, 36, 37, 38, 39], "vari": [5, 22, 25, 35, 40, 43, 45], "variabl": [36, 37, 38, 39, 40, 41, 42, 43, 44], "variat": [6, 10, 15, 22, 23, 24, 25, 36, 37, 38, 39], "variou": [14, 19, 40, 41, 42, 43, 44], "vector": [14, 21], "veloc": [43, 44], "venv": 2, "version": [9, 10, 11, 14, 15, 36, 37, 38, 39, 43, 44, 45], "via": 45, "virtual": 45, "visual": 6, "vpinn": [0, 6, 10, 15, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45], "vtk": [6, 20, 21, 36, 37, 38, 39], "want": 44, "warranti": 3, "we": [1, 4, 7, 8, 36, 37, 38, 39, 40, 41, 42, 43, 44], "weight": [12, 13, 14, 16, 17, 19, 36, 37, 38, 39, 40, 41, 42, 43, 44], "welcom": 1, "well": 1, "what": [40, 41, 42, 43, 44], "when": [36, 37, 38, 39, 40, 41, 42, 43, 44], "where": [24, 25, 36, 37, 38, 39, 40, 41, 42, 43, 44], "whether": [3, 14, 19, 24, 25, 36, 37, 38, 39], "which": [6, 7, 8, 9, 10, 11, 14, 15, 18, 19, 20, 21, 23, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45], "while": [12, 43, 44], "whom": 3, "window": 2, "within": [6, 14, 19, 36, 37, 38, 39], "without": 3, "work": [1, 10, 14, 15, 19, 45], "would": 4, "write": [1, 21, 36, 37, 38, 39], "write_vtk": [21, 36, 37, 38, 39], "written": [21, 40, 43, 44, 45], "x": [7, 8, 9, 10, 11, 12, 14, 15, 19, 21, 26, 27, 28, 29, 31, 33, 36, 37, 38, 39, 40, 41, 42, 43, 44], "x_label": 33, "x_limit": [21, 40, 41, 42, 43], "x_max": [21, 36, 37, 38, 39], "x_min": [21, 36, 37, 38, 39], "x_pde_list": [7, 8, 36, 37, 38, 39, 40, 41, 42, 43, 44], "xi": [9, 10, 11, 12, 13, 15, 16, 17, 18], "xmax": [40, 41, 42, 43], "xmin": [40, 41, 42, 43], "xx": [9, 10, 11, 15], "xy": [9, 10, 11, 15], "y": [7, 8, 9, 10, 11, 12, 14, 15, 19, 21, 26, 27, 28, 29, 31, 33, 36, 37, 38, 39, 40, 41, 42, 43, 44], "y_exact": [36, 37, 38, 39], "y_label": 33, "y_limit": [21, 40, 41, 42, 43], "y_max": [21, 36, 37, 38, 39], "y_min": [21, 36, 37, 38, 39], "y_pred": [36, 37, 38, 39], "yaml": [36, 37, 38, 39, 40, 41, 42, 43, 44], "year": 0, "yet": [14, 19], "ymax": [40, 41, 42, 43], "ymin": [40, 41, 42, 43], "you": [0, 1, 2, 36, 37, 38, 39], "your": [0, 1, 40, 41, 42, 43, 44], "yy": [9, 10, 11, 15], "z": 33, "zero": [12, 40, 44]}, "titles": ["Cite FastVPINNs", "How to Contribute", "Installation", "License", "FastVPINNs Team", "FastVPINNs Tutorials", "FastVPINNs Module Documentation", "fastvpinns.data.datahandler module", "fastvpinns.data.datahandler2d module", "fastvpinns.FE.quad_affine module", "fastvpinns.FE.basis_2d_QN_Jacobi module", "fastvpinns.FE.quad_bilinear module", "fastvpinns.FE.FE2D_Cell module", "fastvpinns.FE.fe2d_setup_main module", "fastvpinns.FE.fespace2d module", "fastvpinns.FE.basis_2d_QN_Jacobi module", "fastvpinns.FE.quadratureformulas module", "fastvpinns.FE.quadratureformulas_quad2d module", "fastvpinns.FE.fe_transformation_2d module", "fastvpinns.FE.fespace module", "fastvpinns.Geometry.geometry module", "fastvpinns.Geometry.geometry_2d module", "fastvpinns.model.model module", "fastvpinns.model.model_hard module", "fastvpinns.model.model_inverse module", "fastvpinns.model.model_inverse_domain module", "fastvpinns.physics.cd2d module", "fastvpinns.physics.cd2d_inverse module", "fastvpinns.physics.cd2d_inverse_domain module", "fastvpinns.physics.helmholtz2d module", "fastvpinns.physics.poisson2d module", "fastvpinns.physics.poisson2d_inverse module", "fastvpinns.utils.compute_utils module", "fastvpinns.utils.plot_utils module", "fastvpinns.utils.print_utils module", "fastvpinns", "Convection Diffusion 2D Example on Circular Domain", "Convection-Diffusion 2D Example on Circular Domain", "Helmholtz 2D Example on Circular Domain", "Poisson 2D Example on Circular Domain", "Solving forward problems with FastVPINNs : Enforcing hard boundary constraints with an ansatz function.", "Solving forward problems with FastVPINNs : Helmholtz - 2D", "Solving forward problems with FastVPINNs : Poisson - 2D", "Solving Inverse Problems with FastVPINNs : Estimation of uniform diffusion parameter on a quadrilateral geometry.", "Solving Inverse Problems with FastVPINNs : Estimation of spatially varying parameter on a complex geometry.", "Welcome to FastVPINNs\u2019s documentation!"], "titleterms": {"": 45, "2d": [36, 37, 38, 39, 41, 42], "all": [36, 37, 38, 39], "an": [2, 40, 43], "ansatz": 40, "api": 45, "basis_2d_qn_jacobi": [10, 15], "bilinear": [36, 37, 38, 39, 40, 41, 42, 43, 44], "boundari": [5, 36, 37, 38, 39, 40, 41, 42, 43, 44], "cd2d": 26, "cd2d_exampl": 36, "cd2d_gear_exampl": 37, "cd2d_invers": 27, "cd2d_inverse_domain": 28, "circular": [36, 37, 38, 39], "cite": 0, "code": [36, 37, 38, 39], "coeffici": 6, "commun": 45, "complex": [5, 44], "comput": [36, 37, 38, 39, 44], "compute_util": 32, "condit": [36, 37, 38, 39, 40, 41, 42, 43, 44], "constant": 6, "constraint": [5, 40], "content": [36, 37, 38, 39, 40, 41, 42, 43, 44], "contribut": 1, "convect": [36, 37], "data": [6, 7, 8], "datahandl": [7, 36, 37, 38, 39], "datahandler2d": 8, "defin": [36, 37, 38, 39, 40, 41, 42, 43, 44], "diffus": [36, 37, 43], "document": [6, 45], "domain": [36, 37, 38, 39, 44], "element": [6, 36, 37, 38, 39, 40, 41, 42, 43, 44], "enforc": 40, "environ": 2, "estim": [43, 44], "exact": [36, 37, 38, 39], "exampl": [36, 37, 38, 39, 40, 41, 42, 43, 44, 45], "experiment": [36, 37, 38, 39], "fastvpinn": [0, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45], "fe": [6, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 40, 41, 42, 43, 44], "fe2d_cel": 12, "fe2d_setup_main": 13, "fe_transformation_2d": 18, "fespac": [19, 36, 37, 38, 39], "fespace2d": 14, "file": [36, 37, 38, 39, 40, 41, 42, 43, 44], "finit": [6, 36, 37, 38, 39, 40, 41, 42, 43, 44], "forc": [40, 41, 42, 43, 44], "form": [36, 37, 38, 39], "forward": [5, 6, 40, 41, 42], "from": [2, 36, 37, 38, 39], "function": [6, 40, 41, 42, 43, 44], "geometri": [5, 6, 20, 21, 36, 37, 38, 39, 40, 41, 42, 43, 44], "geometry_2d": [21, 40, 41, 42, 43, 44], "get": 45, "hard": [5, 40], "helmholtz": [38, 41], "helmholtz2d": 29, "helmholtz_exampl": 38, "how": 1, "import": [36, 37, 38, 39, 40, 41, 42, 43, 44], "indic": 45, "inform": 45, "input": [36, 37, 38, 39, 40, 41, 42, 43, 44], "instal": 2, "instanti": [40, 41, 42, 43], "invers": [5, 6, 43, 44], "librari": [36, 37, 38, 39], "licens": 3, "log": [36, 37, 38, 39, 40, 41, 42, 43, 44], "main": [36, 37, 38, 39, 40, 41, 42, 43, 44], "main_cd2d": [36, 37], "main_helmholtz": 38, "main_poisson2d": 39, "mesh": 5, "method": [40, 41, 42, 43, 44], "model": [6, 22, 23, 24, 25, 36, 37, 38, 39, 40, 41, 42, 43, 44], "model_hard": 23, "model_invers": 24, "model_inverse_domain": 25, "modul": [6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34], "network": 45, "neural": 45, "object": [40, 41, 42, 43, 44], "output": [36, 37, 38, 39], "paramet": [36, 37, 38, 39, 40, 41, 42, 43, 44], "pde": [36, 37, 38, 39, 40, 41, 42, 43, 44], "physic": [6, 26, 27, 28, 29, 30, 31, 45], "pip": 2, "plot": [36, 37, 38, 39], "plot_util": 33, "poisson": [39, 42], "poisson2d": 30, "poisson2d_invers": 31, "post": [36, 37, 38, 39], "pre": [36, 37, 38, 39], "print_util": 34, "problem": [5, 6, 40, 41, 42, 43, 44, 45], "py": [36, 37, 38, 39], "quad_affin": 9, "quad_bilinear": 11, "quadratur": 6, "quadratureformula": 16, "quadratureformulas_quad2d": 17, "quadrilater": 43, "read": [36, 37, 38, 39, 40, 41, 42, 43, 44], "refer": [36, 37, 38, 39, 40, 41, 42, 43, 44, 45], "relev": [40, 41, 42, 43, 44], "requir": [36, 37, 38, 39], "run": [36, 37, 38, 39], "save": [36, 37, 38, 39], "set": [2, 36, 37, 38, 39, 40, 41, 42, 43, 44], "setup": [6, 36, 37, 38, 39], "sin_co": 39, "solut": [36, 37, 38, 39, 40, 41, 42, 43, 44], "solv": [40, 41, 42, 43, 44], "sourc": [2, 36, 37, 38, 39], "space": [36, 37, 38, 39, 40, 41, 42, 43, 44], "spatial": [6, 44], "start": 45, "step": [36, 37, 38, 39], "tabl": 45, "target": [43, 44], "team": 4, "term": [36, 37, 38, 39], "test": [6, 43, 44], "train": [36, 37, 38, 39, 40], "transform": 6, "tutori": 5, "type": 6, "uniform": [5, 43], "up": [2, 36, 37, 38, 39, 40, 41, 42, 43, 44], "util": [6, 32, 33, 34], "valu": [40, 41, 42, 43, 44], "vari": [6, 44], "variat": 45, "via": 2, "virtual": 2, "welcom": 45}}) \ No newline at end of file