diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index e29fb69e..3f8b5059 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -1,6 +1,7 @@ name: Run Python Tests on: + workflow_dispatch: push: branches: [ main megha] pull_request: diff --git a/.gitignore b/.gitignore index f9064758..ea40df8d 100644 --- a/.gitignore +++ b/.gitignore @@ -8,7 +8,7 @@ __pycache__/ # Distribution / packaging .Python -build/ +src/pyVertexModel/Kg/build/ develop-eggs/ dist/ downloads/ @@ -186,3 +186,5 @@ data/ .idea/misc.xml *.db + +*.o diff --git a/.idea/pyVertexModel.iml b/.idea/pyVertexModel.iml index 8fd60d93..6625830e 100644 --- a/.idea/pyVertexModel.iml +++ b/.idea/pyVertexModel.iml @@ -4,7 +4,7 @@ - + diff --git a/Tests/test_cell.py b/Tests/test_cell.py index a0bbaf14..0df14c3b 100644 --- a/Tests/test_cell.py +++ b/Tests/test_cell.py @@ -4,7 +4,6 @@ from Tests.tests import Tests, load_data from src.pyVertexModel.geometry.cell import Cell - class TestCell(Tests): def test_compute_cell_area(self): geo_test, _, _ = load_data('Geo_var_3x3_stretch.mat') @@ -78,3 +77,17 @@ def test_copy(self): self.assertEqual(original_cell.ID, copied_cell.ID) self.assertTrue(np.array_equal(original_cell.X, copied_cell.X)) self.assertTrue(np.array_equal(original_cell.T, copied_cell.T)) + + def test_compute_cell_area_edge_cases(self): + geo_test, _, _ = load_data('Geo_var_3x3_stretch.mat') + + # Test with zero-area cells + geo_test.Cells[0].X = np.array([[0, 0], [0, 0], [0, 0]]) # Degenerate cell + geo_test.Cells[0].compute_area() + self.assertEqual(geo_test.Cells[0].Area, 0) + + # Test with very large area + geo_test.Cells[1].X = np.array([[1e6, 1e6], [1e7, 1e7], [1e8, 1e8]]) # Extreme values + geo_test.Cells[1].compute_area() + self.assertTrue(geo_test.Cells[1].Area > 0) # a non-zero area + diff --git a/Tests/test_geo.py b/Tests/test_geo.py index 4fa869a7..5617166c 100644 --- a/Tests/test_geo.py +++ b/Tests/test_geo.py @@ -5,6 +5,7 @@ from src.pyVertexModel.algorithm.vertexModelVoronoiFromTimeImage import VertexModelVoronoiFromTimeImage from src.pyVertexModel.geometry.geo import Geo, get_node_neighbours_per_domain from src.pyVertexModel.util.utils import load_state, ismember_rows +from Tests.tests import Tests, load_data, assert_matrix def check_if_cells_are_the_same(geo_expected, geo_test): diff --git a/Tests/test_vertexModel.py b/Tests/test_vertexModel.py index 3229b0c7..9cafd46c 100644 --- a/Tests/test_vertexModel.py +++ b/Tests/test_vertexModel.py @@ -8,10 +8,11 @@ from Tests.tests import Tests, assert_matrix, load_data, assert_array1D from src.pyVertexModel.algorithm import newtonRaphson from src.pyVertexModel.algorithm.newtonRaphson import newton_raphson +from src.pyVertexModel.algorithm.vertexModel import create_tetrahedra from src.pyVertexModel.algorithm.vertexModelBubbles import build_topo, SeedWithBoundingBox, generate_first_ghost_nodes, \ delaunay_compute_entities, VertexModelBubbles from src.pyVertexModel.algorithm.vertexModelVoronoiFromTimeImage import build_triplets_of_neighs, calculate_neighbours, \ - VertexModelVoronoiFromTimeImage, create_tetrahedra, add_tetrahedral_intercalations, build_2d_voronoi_from_image, \ + VertexModelVoronoiFromTimeImage, add_tetrahedral_intercalations, build_2d_voronoi_from_image, \ populate_vertices_info, calculate_vertices, get_four_fold_vertices, divide_quartets_neighbours, process_image from src.pyVertexModel.geometry.degreesOfFreedom import DegreesOfFreedom from src.pyVertexModel.util.utils import save_backup_vars @@ -296,7 +297,7 @@ def test_create_tetrahedra(self): # Test if initialize geometry function does not change anything Twg_test = create_tetrahedra(traingles_connectivity, neighbours_network, edges_of_vertices, x_internal, - x_face_ids, x_vertices_ids, x) + x_face_ids, x_vertices_ids) # Check if the test and expected are the same assert_matrix(Twg_test, mat_info['Twg']) diff --git a/Tests/tests.py b/Tests/tests.py index fb1be981..7cfe13e7 100644 --- a/Tests/tests.py +++ b/Tests/tests.py @@ -1,15 +1,14 @@ import unittest -from os.path import exists - +import scipy.io import numpy as np -import scipy +from os.path import exists, abspath from src.pyVertexModel.geometry.geo import Geo from src.pyVertexModel.parameters.set import Set - +from src.pyVertexModel.Kg import kg_functions def load_data(file_name, return_geo=True): - test_dir = 'Tests/data/%s' % file_name + test_dir = abspath('Tests/data/%s' % file_name) if exists(test_dir): mat_info = scipy.io.loadmat(test_dir) else: @@ -23,10 +22,8 @@ def load_data(file_name, return_geo=True): if 'Set' in mat_info.keys(): set_test = Set(mat_info['Set']) - # Set the output folder to the test directory if it is not set if set_test.OutputFolder.__eq__(b'') or set_test.OutputFolder is None: set_test.OutputFolder = '../Result/Test' - else: set_test = None else: @@ -40,9 +37,27 @@ def assert_matrix(k_expected, k): np.testing.assert_allclose(k_expected, k, rtol=1e-3, atol=1e-1) -def assert_array1D(g_expected, g): +def assert_array1D(array1, array2): np.testing.assert_allclose(g_expected, g, rtol=1e-3, atol=1e-1) class Tests(unittest.TestCase): - pass + + def test_load_data_geo(self): + geo_test, set_test, mat_info = load_data('Geo_3x3_dofs_expected.mat') + self.assertIsNotNone(geo_test) + self.assertTrue('Geo' in mat_info) + + def test_load_data_set(self): + geo_test, set_test, mat_info = load_data('Geo_var_3x3_stretch.mat') + self.assertIsNotNone(set_test) + self.assertTrue('Set' in mat_info) + + def test_assert_matrix(self): + k_expected = np.array([[1, 2], [3, 4]]) + k = np.array([[1, 2], [3, 4]]) + assert_matrix(k_expected, k) + + def test_load_data_invalid_file(self): + with self.assertRaises(FileNotFoundError): + load_data('invalid_file.mat') diff --git a/pyproject.toml b/pyproject.toml index d8d0e2a9..7d1f77f8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -15,14 +15,17 @@ dynamic = [ ] dependencies = [ "cython", - "numpy", + "numpy==1.26.4", "scipy", "pillow", "scikit-image", "cython", "vtk", "pandas", - "networkx" + "networkx", + "pyvista", + "scikit-learn", + "matplotlib", ] [tool.coverage] diff --git a/src/pyVertexModel/Kg/kg_functions.pyx b/src/pyVertexModel/Kg/kg_functions.pyx index 3ead78aa..f9ce87a4 100644 --- a/src/pyVertexModel/Kg/kg_functions.pyx +++ b/src/pyVertexModel/Kg/kg_functions.pyx @@ -4,6 +4,8 @@ import cython import numpy as np cimport numpy as np +np.import_array() + # RUN IT LIKE: python setup.py build_ext --inplace @cython.wraparound(False) diff --git a/src/pyVertexModel/analysis/analyse_in_vivo_ablation_data.py b/src/pyVertexModel/analysis/analyse_in_vivo_ablation_data.py index d1f5a367..18c80609 100644 --- a/src/pyVertexModel/analysis/analyse_in_vivo_ablation_data.py +++ b/src/pyVertexModel/analysis/analyse_in_vivo_ablation_data.py @@ -1,4 +1,3 @@ -from datetime import datetime import os import numpy as np diff --git a/src/pyVertexModel/analysis/analyse_results_excel.py b/src/pyVertexModel/analysis/analyse_results_excel.py index 4e01d8d3..cd4dea06 100644 --- a/src/pyVertexModel/analysis/analyse_results_excel.py +++ b/src/pyVertexModel/analysis/analyse_results_excel.py @@ -1,8 +1,6 @@ -import numpy as np +import matplotlib.pyplot as plt import pandas as pd import seaborn as sns -import matplotlib.pyplot as plt -from scipy.interpolate import griddata # Read excel into a pandas dataframe results_excel = pd.read_excel('data/simulations_results/all_files_features.xlsx') diff --git a/src/pyVertexModel/analysis/analyse_simulation.py b/src/pyVertexModel/analysis/analyse_simulation.py index 1c38ea1f..64f44370 100644 --- a/src/pyVertexModel/analysis/analyse_simulation.py +++ b/src/pyVertexModel/analysis/analyse_simulation.py @@ -1,7 +1,7 @@ import os import pickle -import cv2 +import cv2 import numpy as np import pandas as pd from matplotlib import pyplot as plt diff --git a/src/pyVertexModel/analysis/analyse_simulations.py b/src/pyVertexModel/analysis/analyse_simulations.py index 85e810fc..1fb60e01 100644 --- a/src/pyVertexModel/analysis/analyse_simulations.py +++ b/src/pyVertexModel/analysis/analyse_simulations.py @@ -3,8 +3,7 @@ import numpy as np import pandas as pd -from src.pyVertexModel.analysis.analyse_simulation import analyse_simulation, analyse_edge_recoil, create_video -from src.pyVertexModel.util.utils import save_variables, load_variables +from src.pyVertexModel.analysis.analyse_simulation import analyse_simulation, create_video folder = '/media/pablo/d7c61090-024c-469a-930c-f5ada47fb049/PabloVicenteMunuera/VertexModel/pyVertexModel/Result/final_results' all_files_features = [] diff --git a/src/pyVertexModel/geometry/geo.py b/src/pyVertexModel/geometry/geo.py index ae6191e3..a231ec42 100644 --- a/src/pyVertexModel/geometry/geo.py +++ b/src/pyVertexModel/geometry/geo.py @@ -3,9 +3,7 @@ import numpy as np import vtk -from numpy.ma.extras import setxor1d from scipy.spatial import ConvexHull -from torch.fx.experimental.unification.unification_tools import get_in from src.pyVertexModel.Kg.kg import add_noise_to_parameter from src.pyVertexModel.geometry import face, cell @@ -797,6 +795,8 @@ def check_ys_and_faces_have_not_changed(self, new_tets, old_tets, old_geo): assert np.all(self.Cells[cell_id].Faces[id_with_new_index].Centre == c_face.Centre) + + def add_and_rebuild_cells(self, old_geo, old_tets, new_tets, y_new, c_set, update_measurements): """ Add and rebuild the cells diff --git a/src/pyVertexModel/mesh_remodelling/remodelling.py b/src/pyVertexModel/mesh_remodelling/remodelling.py index 641e5711..3dd5aa0f 100644 --- a/src/pyVertexModel/mesh_remodelling/remodelling.py +++ b/src/pyVertexModel/mesh_remodelling/remodelling.py @@ -5,8 +5,7 @@ import pandas as pd from numpy.ma.extras import setdiff1d -from src.pyVertexModel.algorithm.newtonRaphson import gGlobal, newton_raphson_iteration_explicit -from src.pyVertexModel.geometry.cell import face_centres_to_middle_of_neighbours_vertices +from src.pyVertexModel.algorithm.newtonRaphson import gGlobal from src.pyVertexModel.geometry.face import get_interface from src.pyVertexModel.geometry.geo import edge_valence, get_node_neighbours_per_domain, get_node_neighbours from src.pyVertexModel.mesh_remodelling.flip import y_flip_nm, post_flip diff --git a/src/pyVertexModel/parameters/set.py b/src/pyVertexModel/parameters/set.py index 2046dcaa..f8a21296 100644 --- a/src/pyVertexModel/parameters/set.py +++ b/src/pyVertexModel/parameters/set.py @@ -220,15 +220,15 @@ def update_derived_parameters(self): current_datetime = datetime.now() new_outputFolder = ''.join([PROJECT_DIRECTORY, '/Result/', str(current_datetime.strftime("%m-%d_%H%M%S_")), - 'noise_', '{:0.2e}'.format(self.noise_random), '_bNoise_', '{:0.2e}'.format(self.brownian_motion_scale), - '_lVol_', '{:0.2e}'.format(self.lambdaV), '_refV0_', '{:0.2e}'.format(self.ref_V0), - '_kSubs_', '{:0.2e}'.format(self.kSubstrate), - '_lt_', '{:0.2e}'.format(self.cLineTension), - '_refA0_', '{:0.2e}'.format(self.ref_A0), - '_eARBarrier_', '{:0.2e}'.format(self.lambdaR), - '_RemStiff_', str(self.RemodelStiffness), '_lS1_', '{:0.2e}'.format(self.lambdaS1), - '_lS2_', '{:0.2e}'.format(self.lambdaS2), '_lS3_', '{:0.2e}'.format(self.lambdaS3), - '_ps_', '{:0.2e}'.format(self.purseStringStrength), '_lc_', '{:0.2e}'.format(self.lateralCablesStrength)]) + 'noise_', '{:0.2e}'.format(self.noise_random), '_bNoise_', '{:0.2e}'.format(self.brownian_motion_scale), + '_lVol_', '{:0.2e}'.format(self.lambdaV), '_refV0_', '{:0.2e}'.format(self.ref_V0), + '_kSubs_', '{:0.2e}'.format(self.kSubstrate), + '_lt_', '{:0.2e}'.format(self.cLineTension), + '_refA0_', '{:0.2e}'.format(self.ref_A0), + '_eARBarrier_', '{:0.2e}'.format(self.lambdaR), + '_RemStiff_', str(self.RemodelStiffness), '_lS1_', '{:0.2e}'.format(self.lambdaS1), + '_lS2_', '{:0.2e}'.format(self.lambdaS2), '_lS3_', '{:0.2e}'.format(self.lambdaS3), + '_ps_', '{:0.2e}'.format(self.purseStringStrength), '_lc_', '{:0.2e}'.format(self.lateralCablesStrength)]) self.define_if_not_defined("OutputFolder", new_outputFolder) def stretch(self): @@ -320,7 +320,7 @@ def wing_disc(self): self.lambdaS4 = self.lambdaS2 # VTK - self.VTK = False + self.VTK = True # Implicit vs Explicit self.implicit_method = False @@ -337,7 +337,7 @@ def wound_default(self): self.debris_contribution = np.finfo(float).eps # =========================== Contractility ========================== self.Contractility = True - self.TypeOfPurseString = 0 + self.TypeOfPurseString = 2 # 0: Intensity-based purse string # 1: Strain-based purse string (delayed) # 2: Fixed with linear increase purse string diff --git a/src/pyVertexModel/util/space_exploration.py b/src/pyVertexModel/util/space_exploration.py index 2ee730b7..c1e8eb51 100644 --- a/src/pyVertexModel/util/space_exploration.py +++ b/src/pyVertexModel/util/space_exploration.py @@ -12,6 +12,7 @@ from src.pyVertexModel.parameters.set import Set from src.pyVertexModel.util.utils import load_state, load_variables, save_variables + def objective(trial): """ Objective function to minimize diff --git a/src/pyVertexModel/util/utils.py b/src/pyVertexModel/util/utils.py index b428c6bd..e1ed7f00 100644 --- a/src/pyVertexModel/util/utils.py +++ b/src/pyVertexModel/util/utils.py @@ -6,8 +6,8 @@ import pickle import imageio -import pyvista as pv import numpy as np +import pyvista as pv from scipy.optimize import fsolve