diff --git a/.github/workflows/python-tests.yml b/.github/workflows/python-tests.yml index 2665ad7e..f7978bab 100644 --- a/.github/workflows/python-tests.yml +++ b/.github/workflows/python-tests.yml @@ -17,53 +17,29 @@ jobs: - uses: actions/checkout@v3 - name: Running serial tests run: | - source /home/olender/Firedrakes/newest3/firedrake/bin/activate + source /home/olender/firedrakes/2024_07_19/firedrake/bin/activate pytest --cov-report=xml --cov=spyro test/ - name: Running parallel 3D forward test run: | - source /home/olender/Firedrakes/newest3/firedrake/bin/activate + source /home/olender/firedrakes/2024_07_19/firedrake/bin/activate mpiexec -n 6 pytest test_3d/test_hexahedral_convergence.py mpiexec -n 6 pytest test_parallel/test_forward.py mpiexec -n 6 pytest test_parallel/test_fwi.py - name: Covering parallel 3D forward test continue-on-error: true run: | - source /home/olender/Firedrakes/newest3/firedrake/bin/activate + source /home/olender/firedrakes/2024_07_19/firedrake/bin/activate mpiexec -n 6 pytest --cov-report=xml --cov-append --cov=spyro test_3d/test_hexahedral_convergence.py - name: Covering parallel forward test continue-on-error: true run: | - source /home/olender/Firedrakes/newest3/firedrake/bin/activate + source /home/olender/firedrakes/2024_07_19/firedrake/bin/activate mpiexec -n 6 pytest --cov-report=xml --cov-append --cov=spyro test_parallel/test_forward.py - name: Covering parallel fwi test continue-on-error: true run: | - source /home/olender/Firedrakes/newest3/firedrake/bin/activate + source /home/olender/firedrakes/2024_07_19/firedrake/bin/activate mpiexec -n 6 pytest --cov-report=xml --cov-append --cov=spyro test_parallel/test_fwi.py - # - name: Running serial tests for adjoint - # run: | - # source /home/olender/Firedrakes/main/firedrake/bin/activate - # pytest -n 10 --cov-report=xml --cov-append --cov=spyro test_ad/ - # - name: Running parallel tests - # run: | - # source /home/olender/Firedrakes/main/firedrake/bin/activate - # cp /home/olender/Testing_files/velocity_models/* velocity_models/ - # cp /home/olender/Testing_files/meshes/* meshes/ - # mpiexec -n 10 pytest test_parallel/test_forward.py - # - name: Covering parallel tests - # continue-on-error: true - # run: | - # source /home/olender/Firedrakes/main/firedrake/bin/activate - # cp /home/olender/Testing_files/velocity_models/* velocity_models/ - # cp /home/olender/Testing_files/meshes/* meshes/ - # mpiexec -n 10 pytest --cov-report=xml --cov-append --cov=spyro test_parallel/test_forward.py - # - name: Covering parallel 3D forward test - # continue-on-error: true - # run: | - # source /home/olender/Firedrakes/main/firedrake/bin/activate - # cp /home/olender/Testing_files/velocity_models/* velocity_models/ - # cp /home/olender/Testing_files/meshes/* meshes/ - # mpiexec -n 10 pytest --cov-report=xml --cov-append --cov=spyro test_3d/test_forward_3d.py - name: Uploading coverage to Codecov run: export CODECOV_TOKEN="057ec853-d7ea-4277-819b-0c5ea2f9ff57" && bash <(curl -s https://codecov.io/bash) diff --git a/notebook_tutorials/meshing.html b/notebook_tutorials/meshing.html deleted file mode 100644 index fe948904..00000000 --- a/notebook_tutorials/meshing.html +++ /dev/null @@ -1,8976 +0,0 @@ - - - - - -meshing - - - - - - - - - - - - -
-
- -
-
- -
- - -
-
- -
-
- -
-
- -
- - -
-
- -
-
- -
-
- -
- - -
-
- -
- -
-
- -
- - -
-
- -
- - -
-
- -
- -
-
- -
- -
- - -
-
- -
- -
-
- -
-
- -
-
- -
-
- -
- -
-
- -
- -
-
- -
- -
-
- -
- - -
-
- -
- - -
-
- -
- -
-
- -
- - -
-
- -
- -
- - -
-
- -
- - -
-
- -
- - -
-
- -
- - -
-
- -
- - -
-
- -
-
- - diff --git a/notebook_tutorials/premade_useful_examples.html b/notebook_tutorials/premade_useful_examples.html deleted file mode 100644 index fe6b0895..00000000 --- a/notebook_tutorials/premade_useful_examples.html +++ /dev/null @@ -1,8177 +0,0 @@ - - - - - -premade_useful_examples - - - - - - - - - - - - -
-
- -
- - -
-
- -
-
- -
-
- -
- - -
-
- -
- - -
-
- -
-
- -
- - -
-
- -
- - -
-
- -
-
- -
-
- -
-
- -
- - -
- - -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
- -
-
- -
- - -
-
- -
-
- - diff --git a/notebook_tutorials/simple_forward.html b/notebook_tutorials/simple_forward.html deleted file mode 100644 index a71fb9aa..00000000 --- a/notebook_tutorials/simple_forward.html +++ /dev/null @@ -1,8120 +0,0 @@ - - - - - -simple_forward - - - - - - - - - - - - -
-
- -
-
- -
- -
-
- -
- - -
-
- -
- -
-
- -
- -
-
- -
- -
-
- -
- -
-
- -
- -
-
- -
- -
-
- -
- -
-
- -
- - -
-
- -
- -
-
- -
- -
-
- -
- - -
-
- -
- - -
-
- -
- -
-
- -
- -
-
- -
- - -
-
- -
- - -
-
- - diff --git a/notebook_tutorials/simple_forward_with_overthrust.html b/notebook_tutorials/simple_forward_with_overthrust.html deleted file mode 100644 index d042fc35..00000000 --- a/notebook_tutorials/simple_forward_with_overthrust.html +++ /dev/null @@ -1,8125 +0,0 @@ - - - - - -simple_forward_with_overthrust - - - - - - - - - - - - -
-
- -
-
- -
- -
-
- -
- - -
-
- -
- -
-
- -
- -
-
- -
- -
-
- -
- -
-
- -
- -
-
- -
- -
-
- -
- -
-
- -
- -
-
- -
- -
-
- -
- - -
-
- -
- - -
-
- -
- - -
-
- -
-
- -
- -
-
- -
- - -
-
- - diff --git a/spyro/examples/rectangle.py b/spyro/examples/rectangle.py index 8f2f6693..2b9a1fc7 100644 --- a/spyro/examples/rectangle.py +++ b/spyro/examples/rectangle.py @@ -24,7 +24,7 @@ rectangle_dictionary = {} rectangle_dictionary["options"] = { # simplexes such as triangles or tetrahedra (T) or quadrilaterals (Q) - "cell_type": "Q", + "cell_type": "T", "variant": "lumped", # lumped, equispaced or DG, default is lumped "degree": 4, # p order "dimension": 2, # dimension diff --git a/spyro/solvers/acoustic_solver_construction_no_pml.py b/spyro/solvers/acoustic_solver_construction_no_pml.py index 252c0180..4c4882eb 100644 --- a/spyro/solvers/acoustic_solver_construction_no_pml.py +++ b/spyro/solvers/acoustic_solver_construction_no_pml.py @@ -20,8 +20,10 @@ def construct_solver_or_matrix_no_pml(Wave_object): u_nm1 = fire.Function(V, name="pressure t-dt") u_n = fire.Function(V, name="pressure") + u_np1 = fire.Function(V, name="pressure t+dt") Wave_object.u_nm1 = u_nm1 Wave_object.u_n = u_n + Wave_object.u_np1 = u_np1 Wave_object.current_time = 0.0 dt = Wave_object.dt @@ -35,7 +37,7 @@ def construct_solver_or_matrix_no_pml(Wave_object): ) a = dot(grad(u_n), grad(v)) * dx(scheme=quad_rule) # explicit - B = fire.Function(V) + B = fire.Cofunction(V.dual()) form = m1 + a lhs = fire.lhs(form) diff --git a/spyro/solvers/backward_time_integration.py b/spyro/solvers/backward_time_integration.py index 5b440235..5f9cfdb7 100644 --- a/spyro/solvers/backward_time_integration.py +++ b/spyro/solvers/backward_time_integration.py @@ -72,7 +72,7 @@ def backward_wave_propagator_no_pml(Wave_obj, dt=None): u_n = Wave_obj.u_n u_np1 = fire.Function(Wave_obj.function_space) - rhs_forcing = fire.Function(Wave_obj.function_space) + rhs_forcing = fire.Cofunction(Wave_obj.function_space.dual()) B = Wave_obj.B rhs = Wave_obj.rhs diff --git a/spyro/solvers/mms_acoustic.py b/spyro/solvers/mms_acoustic.py index ccbfb28c..ca21dc81 100644 --- a/spyro/solvers/mms_acoustic.py +++ b/spyro/solvers/mms_acoustic.py @@ -27,8 +27,7 @@ def mms_source_in_space(self): if self.dimension == 2: # xy = fire.project(sin(pi*x)*sin(pi*y), V) # self.q_xy.assign(xy) - xy = fire.project((-(x**2) - x - y**2 + y), V) - self.q_xy.assign(xy) + self.q_xy.interpolate(-(x**2) - x - y**2 + y) elif self.dimension == 3: z = self.mesh_y # xyz = fire.project(sin(pi*x)*sin(pi*y)*sin(pi*z), V) diff --git a/spyro/solvers/time_integration_central_difference.py b/spyro/solvers/time_integration_central_difference.py index 410bf5cd..2c6bf696 100644 --- a/spyro/solvers/time_integration_central_difference.py +++ b/spyro/solvers/time_integration_central_difference.py @@ -1,5 +1,6 @@ import firedrake as fire from firedrake import Constant, dx, dot, grad +import numpy as np from ..io.basicio import parallel_print from . import helpers @@ -47,7 +48,7 @@ def central_difference(Wave_object, source_id=0): u_n = Wave_object.u_n u_np1 = fire.Function(Wave_object.function_space) - rhs_forcing = fire.Function(Wave_object.function_space) + rhs_forcing = fire.Cofunction(Wave_object.function_space.dual()) usol = [ fire.Function(Wave_object.function_space, name="pressure") for t in range(nt) @@ -241,9 +242,9 @@ def central_difference_MMS(Wave_object, source_id=0): u_nm1 = Wave_object.u_nm1 u_n = Wave_object.u_n + u_np1 = Wave_object.u_np1 u_nm1.assign(Wave_object.analytical_solution(t - 2 * dt)) u_n.assign(Wave_object.analytical_solution(t - dt)) - u_np1 = fire.Function(Wave_object.function_space, name="pressure t +dt") u = fire.TrialFunction(Wave_object.function_space) v = fire.TestFunction(Wave_object.function_space) @@ -277,9 +278,7 @@ def central_difference_MMS(Wave_object, source_id=0): B = fire.assemble(rhs, tensor=B) - Wave_object.solver.solve(X, B) - - u_np1.assign(X) + Wave_object.solver.solve(u_np1, B) usol_recv.append( Wave_object.receivers.interpolate(u_np1.dat.data_ro_with_halos[:]) diff --git a/test/test_MMS.py b/test/test_MMS.py index ab2cb44c..cb1da365 100644 --- a/test/test_MMS.py +++ b/test/test_MMS.py @@ -5,28 +5,9 @@ import spyro from .model import dictionary as model - model["acquisition"]["source_type"] = "MMS" -@pytest.fixture(params=["triangle", "square"]) -def mesh_type(request): - if mesh_type == "triangle": - model["cell_type"] = "triangles" - elif mesh_type == "square": - model["cell_type"] = "quadrilaterals" - return request.param - - -@pytest.fixture(params=["lumped", "equispaced"]) -def method_type(request): - if method_type == "lumped": - model["variant"] = "lumped" - elif method_type == "equispaced": - model["variant"] = "equispaced" - return request.param - - def run_solve(model): testmodel = deepcopy(model) @@ -41,7 +22,28 @@ def run_solve(model): return errornorm(u_num, u_an) -def test_method(mesh_type, method_type): +def run_method(mesh_type, method_type): + model["options"]["cell_type"] = mesh_type + model["options"]["variant"] = method_type + print(f"For {mesh_type} and {method_type}") error = run_solve(model) + test = math.isclose(error, 0.0, abs_tol=1e-7) + print(f"Error is {error}") + print(f"Test: {test}") + + assert test + + +def test_method_triangles_lumped(): + run_method("triangles", "lumped") + + +def test_method_quads_lumped(): + run_method("quadrilaterals", "lumped") + + +if __name__ == "__main__": + test_method_triangles_lumped() + test_method_quads_lumped() - assert math.isclose(error, 0.0, abs_tol=1e-7) + print("END") diff --git a/test/test_cpw_calc.py b/test/test_cpw_calc.py index bc5e99c7..35e4e825 100644 --- a/test/test_cpw_calc.py +++ b/test/test_cpw_calc.py @@ -17,7 +17,7 @@ def test_cpw_calc(): "velocity_model_file_name": None, # FEM to evaluate such as `KMV` or `spectral` # (GLL nodes on quads and hexas) - "FEM_method_to_evaluate": "spectral_quadrilateral", + "FEM_method_to_evaluate": "mass_lumped_triangle", "dimension": 2, # Domain dimension. Either 2 or 3. # Either near or line. Near defines a receiver grid near to the source, "receiver_setup": "near", @@ -32,7 +32,7 @@ def test_cpw_calc(): # grid point density to use in the reference case (float) "C_reference": None, "desired_degree": 4, # degree we are calculating G for. (int) - "C_initial": 2.4, # Initial G for line search (float) + "C_initial": 2.2, # Initial G for line search (float) "accepted_error_threshold": 0.05, "C_accuracy": 0.1, } @@ -60,7 +60,8 @@ def test_cpw_calc(): # Check if cpw is within error TOL, starting search at min min = Cpw_calc.find_minimum() - test3 = np.isclose(2.5, min) + print(f"Minimum of {min}") + test3 = np.isclose(2.3, min) print("END") assert all([test1, test2, test3]) diff --git a/test/test_gradient.py b/test/test_gradient.py deleted file mode 100644 index c64c67c4..00000000 --- a/test/test_gradient.py +++ /dev/null @@ -1,254 +0,0 @@ -import numpy as np -import os -from firedrake import * -import spyro -from spyro.domains import quadrature -import pytest - -from .inputfiles.Model1_gradient_2d import model -from .inputfiles.Model1_gradient_2d_pml import model_pml - - -dictionary = {} -dictionary["options"] = { - "cell_type": "T", # simplexes such as triangles or tetrahedra (T) or quadrilaterals (Q) - "variant": "lumped", # lumped, equispaced or DG, default is lumped - "method": "MLT", # (MLT/spectral_quadrilateral/DG_triangle/DG_quadrilateral) You can either specify a cell_type+variant or a method - "degree": 4, # p order - "dimension": 2, # dimension - "automatic_adjoint": False, -} - -# Number of cores for the shot. For simplicity, we keep things serial. -# spyro however supports both spatial parallelism and "shot" parallelism. -dictionary["parallelism"] = { - "type": "automatic", # options: automatic (same number of cores for evey processor) or spatial -} - -# Define the domain size without the PML. Here we'll assume a 0.75 x 1.50 km -# domain and reserve the remaining 250 m for the Perfectly Matched Layer (PML) to absorb -# outgoing waves on three sides (eg., -z, +-x sides) of the domain. -dictionary["mesh"] = { - "Lz": 1.0, # depth in km - always positive # Como ver isso sem ler a malha? - "Lx": 1.0, # width in km - always positive - "Ly": 0.0, # thickness in km - always positive - "mesh_file": None, -} -dictionary[ - "synthetic_data" -] = { # For use only if you are using a synthetic test model or a forward only simulation -adicionar discrição para modelo direto - "real_mesh_file": None, - "real_velocity_file": None, -} -dictionary["inversion"] = { - "perform_fwi": False, # switch to true to make a FWI - "initial_guess_model_file": None, - "shot_record_file": None, - "optimization_parameters": None, -} - -# Specify a 250-m PML on the three sides of the domain to damp outgoing waves. -dictionary["absorving_boundary_conditions"] = { - "status": False, # True or false - "outer_bc": "non-reflective", # None or non-reflective (outer boundary condition) - "damping_type": "polynomial", # polynomial, hyperbolic, shifted_hyperbolic - "exponent": 2, # damping layer has a exponent variation - "cmax": 4.7, # maximum acoustic wave velocity in PML - km/s - "R": 1e-6, # theoretical reflection coefficient - "lz": 0.25, # thickness of the PML in the z-direction (km) - always positive - "lx": 0.25, # thickness of the PML in the x-direction (km) - always positive - "ly": 0.0, # thickness of the PML in the y-direction (km) - always positive -} - -# Create a source injection operator. Here we use a single source with a -# Ricker wavelet that has a peak frequency of 8 Hz injected at the center of the mesh. -# We also specify to record the solution at 101 microphones near the top of the domain. -# This transect of receivers is created with the helper function `create_transect`. -dictionary["acquisition"] = { - "source_type": "ricker", - "source_locations": [(-0.1, 0.5)], - "frequency": 5.0, - "delay": 1.0, - "receiver_locations": spyro.create_transect((-0.10, 0.1), (-0.10, 0.9), 20), -} - -# Simulate for 2.0 seconds. -dictionary["time_axis"] = { - "initial_time": 0.0, # Initial time for event - "final_time": 2.00, # Final time for event - "dt": 0.001, # timestep size - "amplitude": 1, # the Ricker has an amplitude of 1. - "output_frequency": 100, # how frequently to output solution to pvds - Perguntar Daiane ''post_processing_frequnecy' - "gradient_sampling_frequency": 100, # how frequently to save solution to RAM - Perguntar Daiane 'gradient_sampling_frequency' -} -dictionary["visualization"] = { - "forward_output": True, - "output_filename": "results/forward_output.pvd", - "fwi_velocity_model_output": False, - "velocity_model_filename": None, - "gradient_output": False, - "gradient_filename": None, - "adjoint_output": False, - "adjoint_filename": None, -} -outfile_total_gradient = File(os.getcwd() + "/results/Gradient.pvd") - -# forward = spyro.solvers.forward -# gradient = spyro.solvers.gradient -functional = spyro.utils.compute_functional - - -def _make_vp_exact(V, mesh): - """Create a circle with higher velocity in the center""" - z, x = SpatialCoordinate(mesh) - vp_exact = Function(V).interpolate( - 4.0 + 1.0 * tanh(10.0 * (0.5 - sqrt((z - 1.5) ** 2 + (x + 1.5) ** 2))) - ) - File("exact_vel.pvd").write(vp_exact) - return vp_exact - - -def _make_vp_exact_pml(V, mesh): - """Create a half space""" - z, x = SpatialCoordinate(mesh) - velocity = conditional(z > -0.5, 1.5, 4.0) - vp_exact = Function(V, name="vp").interpolate(velocity) - File("exact_vel.pvd").write(vp_exact) - return vp_exact - - -def _make_vp_guess(V, mesh): - """The guess is a uniform velocity of 4.0 km/s""" - z, x = SpatialCoordinate(mesh) - vp_guess = Function(V).interpolate(4.0 + 0.0 * x) - File("guess_vel.pvd").write(vp_guess) - return vp_guess - - -@pytest.mark.skip(reason="not yet implemented") -def test_gradient(): - _test_gradient(model) - - -@pytest.mark.skip(reason="no way of currently testing this") -def test_gradient_pml(): - _test_gradient(model_pml, pml=True) - - -def _test_gradient(options, pml=False): - comm = spyro.utils.mpi_init(options) - - mesh, V = spyro.basicio.read_mesh(options, comm) - - if pml: - vp_exact = _make_vp_exact_pml(V, mesh) - z, x = SpatialCoordinate(mesh) - Lx = model_pml["mesh"]["Lx"] - Lz = model_pml["mesh"]["Lz"] - x1 = 0.0 - z2 = -Lz - boxx1 = Function(V).interpolate(conditional(x > x1, 1.0, 0.0)) - boxx2 = Function(V).interpolate(conditional(x < Lx, 1.0, 0.0)) - boxz1 = Function(V).interpolate(conditional(z > z2, 1.0, 0.0)) - mask = Function(V).interpolate(boxx1 * boxx2 * boxz1) - File("mask.pvd").write(mask) - else: - vp_exact = _make_vp_exact(V, mesh) - - mask = Function(V).assign(1.0) - - vp_guess = _make_vp_guess(V, mesh) - - sources = spyro.Sources(options, mesh, V, comm) - - receivers = spyro.Receivers(options, mesh, V, comm) - - wavelet = spyro.full_ricker_wavelet( - options["timeaxis"]["dt"], - options["timeaxis"]["tf"], - options["acquisition"]["frequency"], - ) - - # simulate the exact model - p_exact, p_exact_recv = forward( - options, - mesh, - comm, - vp_exact, - sources, - wavelet, - receivers, - ) - - # simulate the guess model - p_guess, p_guess_recv = forward( - options, - mesh, - comm, - vp_guess, - sources, - wavelet, - receivers, - ) - - misfit = p_exact_recv - p_guess_recv - - qr_x, _, _ = quadrature.quadrature_rules(V) - - Jm = functional(options, misfit) - print("\n Cost functional at fixed point : " + str(Jm) + " \n ") - - # compute the gradient of the control (to be verified) - dJ = gradient(options, mesh, comm, vp_guess, receivers, p_guess, misfit) - dJ.dat.data[:] = dJ.dat.data[:] * mask.dat.data[:] - File("gradient.pvd").write(dJ) - - steps = [1e-3, 1e-4, 1e-5] # , 1e-6] # step length - - delta_m = Function(V) # model direction (random) - delta_m.assign(dJ) - - # this deepcopy is important otherwise pertubations accumulate - vp_original = vp_guess.copy(deepcopy=True) - - errors = [] - for step in steps: # range(3): - # steps.append(step) - # perturb the model and calculate the functional (again) - # J(m + delta_m*h) - vp_guess = vp_original + step * delta_m - _, p_guess_recv = forward( - options, - mesh, - comm, - vp_guess, - sources, - wavelet, - receivers, - ) - - Jp = functional(options, p_exact_recv - p_guess_recv) - projnorm = assemble(mask * dJ * delta_m * dx(scheme=qr_x)) - fd_grad = (Jp - Jm) / step - print( - "\n Cost functional for step " - + str(step) - + " : " - + str(Jp) - + ", fd approx.: " - + str(fd_grad) - + ", grad'*dir : " - + str(projnorm) - + " \n ", - ) - - errors.append(100 * ((fd_grad - projnorm) / projnorm)) - # step /= 2 - - # all errors less than 1 % - errors = np.array(errors) - assert (np.abs(errors) < 5.0).all() - - -if __name__ == "__main__": - test_gradient(model) diff --git a/test/test_gradient_2d.py b/test/test_gradient_2d.py index d3ebac60..3b900894 100644 --- a/test/test_gradient_2d.py +++ b/test/test_gradient_2d.py @@ -67,7 +67,7 @@ def check_gradient(Wave_obj_guess, dJ, rec_out_exact, Jm, plot=False): dictionary = {} dictionary["options"] = { - "cell_type": "Q", # simplexes such as triangles or tetrahedra (T) or quadrilaterals (Q) + "cell_type": "T", # simplexes such as triangles or tetrahedra (T) or quadrilaterals (Q) "variant": "lumped", # lumped, equispaced or DG, default is lumped "degree": 4, # p order "dimension": 2, # dimension diff --git a/test/test_time_convergence.py b/test/test_time_convergence.py index a92f66ea..8a014dfd 100644 --- a/test/test_time_convergence.py +++ b/test/test_time_convergence.py @@ -18,7 +18,7 @@ def run_forward(dt): dictionary = {} dictionary["options"] = { - "cell_type": "Q", # simplexes such as triangles or tetrahedra (T) or quadrilaterals (Q) + "cell_type": "T", # simplexes such as triangles or tetrahedra (T) or quadrilaterals (Q) "variant": "lumped", # lumped, equispaced or DG, default is lumped "method":"MLT", # (MLT/spectral_quadrilateral/DG_triangle/DG_quadrilateral) You can either specify a cell_type+variant or a method "degree": 4, # p order "dimension": 2, # dimension diff --git a/velocity_models/tutorial b/velocity_models/tutorial deleted file mode 100644 index 81a389f5..00000000 Binary files a/velocity_models/tutorial and /dev/null differ