def test_distance(): exp_organo = generate_ring(3, 1, 2) th_organo = generate_ring(3, 1, 2) exp_organo.vert_df.loc[0, 'x'] += 1 distance = _distance(exp_organo, th_organo) assert np.all( np.equal(distance, np.concatenate(([1], np.zeros(exp_organo.Nv - 1)))))
def test_distance_regularized(): exp_organo = generate_ring(3, 1, 2) th_organo = generate_ring(3, 1, 2) geom.update_all(exp_organo) geom.update_all(th_organo) specs = { 'face': { 'is_alive': 1, 'prefered_area': 1.1 * th_organo.face_df.area, 'area_elasticity': 1, }, 'edge': { 'ux': 0., 'uy': 0., 'uz': 0., 'line_tension': 0.01, 'is_active': 1 }, 'vert': { 'adhesion_strength': 0., 'x_ecm': 0., 'y_ecm': 0., 'is_active': 1 }, 'settings': { 'lumen_elasticity': 0.01, 'lumen_prefered_vol': th_organo.settings['lumen_volume'], 'lumen_volume': th_organo.settings['lumen_volume'] } } exp_organo.update_specs(specs, reset=True) th_organo.update_specs(specs, reset=True) param_tension_only = {('edge', 'line_tension'): np.ones(12)} param_with_lumen = { ('edge', 'line_tension'): np.ones(12), ('lumen_prefered_vol', None): th_organo.settings['lumen_volume'] } for basal_reg, apical_reg in ((0, 0), (0, 1), (1, 0), (1, 1)): for variables in (param_with_lumen, param_tension_only): to_regularize = {'dic': {'apical': basal_reg, 'basal': apical_reg}} reg_weight = 0.01 energy_opt = {'options': {'gtol': 1e-1, 'ftol': 1e-1}} exp_organo.vert_df.loc[0, 'x'] += 1 res = distance_regularized(exp_organo, th_organo, variables, Solver, geom, model, **energy_opt) assert isinstance(res, np.ndarray) assert res.all() >= 0 assert res.any() > 0
def _create_org(): organo = generate_ring(3, 1, 2) geom.update_all(organo) alpha = 1 + 1 / (20 * (organo.settings['R_out'] - organo.settings['R_in'])) specs = { 'face': { 'is_alive': 1, 'prefered_area': list(alpha * organo.face_df.area.values), 'area_elasticity': 1., }, 'edge': { 'ux': 0., 'uy': 0., 'uz': 0., 'line_tension': 0.1, 'is_active': 1 }, 'vert': { 'adhesion_strength': 0., 'x_ecm': 0., 'y_ecm': 0., 'is_active': 1 }, 'settings': { 'lumen_elasticity': 0.1, 'lumen_prefered_vol': organo.settings['lumen_volume'], 'lumen_volume': organo.settings['lumen_volume'] } } organo.update_specs(specs, reset=True) geom.update_all(organo) return organo
def test_infer_pol(): organo = generate_ring(3, 1, 2) pol_organo = organo.copy() pol_organo.vert_df.loc[pol_organo.basal_verts, ('x', 'y')] *= 1.1 geom.update_all(pol_organo) for val in _infer_pol(pol_organo): assert round(val, 9) == 0.9
def test_tension_bounds(): organo = generate_ring(3, 1, 2) organo.edge_df.loc[:, 'line_tension'] = np.ones(12) organo.edge_df.loc[(0, 1), 'line_tension'] = [-1, 2 * 1e3] penalties = _tension_bounds(organo) assert len(penalties) == 3 * organo.Nf assert penalties[0] == 1e3 assert penalties[1] == 0 assert np.argwhere(penalties != 0).squeeze() == np.array(0)
def test_right_side(): organo = generate_ring(3, 1, 2) pol_organo = organo.copy() pol_organo.vert_df.loc[pol_organo.basal_verts, ('x', 'y')] *= 1.1 geom.update_all(pol_organo) cst = _right_side(pol_organo) assert isinstance(cst, np.ndarray) assert np.array_equal(cst.shape, (15, )) assert np.array_equal(cst[:12], np.zeros(12)) assert not np.isnan(cst[12:]).any()
def test_t_per_cell_coefs(): organo = generate_ring(3, 1, 2) t_per_cell = _t_per_cell_coefs(organo, _get_sim_param(3, 1, 2), _infer_pol(organo)) assert isinstance(t_per_cell, np.ndarray) assert np.array_equal(t_per_cell.shape, (3, 13)) assert np.array_equal(t_per_cell[:, :3], np.eye(3)) assert np.array_equal(t_per_cell[:, 3:6], np.eye(3)) assert np.array_equal( t_per_cell[:, 6:9], np.roll(np.eye(3) + np.roll(np.eye(3), 1, axis=0), 1, axis=1)) assert np.array_equal(t_per_cell[:, 9:], np.zeros((3, 4)))
def mesh_from_data(centers, inner_contour, outer_contour): """Creates an annular organoid from image data """ Nf = centers.shape[0] print(tmp_eptm.datasets[elem][columns], values) # Organize centers clockwize origin = centers.mean(axis=1) shifted_centers = centers - origin[np.newaxis, :] thetas = np.arctan2(shifted_centers[:, 1], shifted_centers[:, 0]) centers = centers.take(np.argsort(thetas)) inner_vs, outer_vs = get_bissecting_vertices(centers, inner_contour, outer_contour) R_in = np.linalg.norm(inner_vs - inner_vs.mean(axis=1), axis=0).mean() R_out = np.linalg.norm(outer_vs - outer_vs.mean(axis=1), axis=0).mean() organo = generate_ring(Nf, R_in, R_out) organo.vert_df.loc[organo.apical_verts, organo.coords] = inner_vs[::-1] organo.vert_df.loc[organo.basal_verts, organo.coords] = outer_vs[::-1] AnnularGeometry.update_all(organo) specs = { 'face': { 'is_alive': 1, 'prefered_area': organo.face_df.area.mean(), 'area_elasticity': 1, }, 'edge': { 'ux': 0., 'uy': 0., 'fx': 0., 'fy': 0., 'sx': 0., # source and target coordinates 'sy': 0., 'tx': 0., 'ty': 0., 'line_tension': 1e-3, 'is_active': 1 }, 'vert': { 'is_active': 1 }, 'settings': { 'lumen_elasticity': 10, 'lumen_prefered_vol': organo.settings['lumen_volume'], 'lumen_volume': organo.settings['lumen_volume'] } } organo.update_specs(specs, reset=True) return organo
def test_prepare_tensions(): organo = generate_ring(3, 1, 2) organo.edge_df.loc[:, 'line_tension'] = np.ones(12) tension_array = organo.edge_df.loc[:, 'line_tension'][:3 * organo.Nf] tension_array[0] += 1 tension_array[3 * organo.Nf - 1] += 1 tensions = prepare_tensions(organo, tension_array) assert len(tensions) == 4 * organo.Nf assert np.all( np.equal(tensions[:3 * organo.Nf], tension_array[:3 * organo.Nf])) assert np.all( np.equal(np.roll(tensions[3 * organo.Nf:], 1), tension_array[2 * organo.Nf:]))
def create_organo(nb_cells, r_in, r_out, seed=None, rot=None, geom=geom): organo = generate_ring(nb_cells, r_in, r_out) Nf = organo.Nf geom.update_all(organo) alpha = 1 + 1 / (20 * (organo.settings['R_out'] - organo.settings['R_in'])) specs = { 'face': { 'is_alive': 1, 'prefered_area': organo.face_df.area, 'area_elasticity': 1., }, 'edge': { 'ux': 0., 'uy': 0., 'uz': 0., 'line_tension': 0.1, 'is_active': 1 }, 'vert': { 'adhesion_strength': 0.01, 'x_ecm': 0., 'y_ecm': 0., 'is_active': 1 }, 'settings': { 'lumen_elasticity': 1., 'lumen_prefered_vol': organo.settings['lumen_volume'], 'lumen_volume': organo.settings['lumen_volume'] } } organo.update_specs(specs, reset=True) normalize_scale(organo, geom, refer='edges') geom.update_all(organo) if seed is not None: symetric_tensions = set_init_point(organo.settings['R_in'], organo.settings['R_out'], organo.Nf, alpha) sin_mul = 1 + (np.sin( np.linspace(0, 2 * np.pi, organo.Nf, endpoint=False)))**2 organo.face_df.prefered_area *= np.random.normal(1.0, 0.05, organo.Nf) organo.edge_df.line_tension = prepare_tensions(organo, symetric_tensions) organo.edge_df.loc[:Nf - 1, 'line_tension'] *= sin_mul * np.random.normal( 1.0, 0.05, organo.Nf) geom.update_all(organo) if rot is not None: organo.vert_df.loc[:, 'x'] = (organo.vert_df.x.copy() * np.cos(rot) - organo.vert_df.y.copy() * np.sin(rot)) print( 'rotated x', organo.vert_df.x.copy() * np.cos(rot) - organo.vert_df.y.copy() * np.sin(rot)) organo.vert_df.loc[:, 'y'] = (organo.vert_df.x.copy() * np.sin(rot) + organo.vert_df.y.copy() * np.cos(rot)) print( 'rotated y', organo.vert_df.x.copy() * np.sin(rot) + organo.vert_df.y.copy() * np.cos(rot)) geom.update_all(organo) organo.vert_df[['x_ecm', 'y_ecm']] = organo.vert_df[['x', 'y']] organo.vert_df.loc[organo.basal_verts, 'adhesion_strength'] = 0.01 new_tensions = organo.edge_df.line_tension organo.edge_df.loc[:, 'line_tension'] = new_tensions return organo
def generate_ring_from_image( brightfield_path, dapi_path, scp_model_path=None, threshold=28, blur=9, rol_window_inside=100, rol_window_outside=20, ): """Create an organo mesh of class AnnularSheet from a brightfield image and a CellProfiler DAPI analysis csv file Parameters ---------- brightfield_path : string path to the brightfield image dapi_path : string path to the DAPI image scp_model_path : string path to the stardist model threshold: int >=0 threshold to apply to the brightfield image blur: int >=0 gaussian blur to apply to the brightfield image rol_window_inside: int > 0. Length of the window of the rolling mean on apical contour. rol_window_outside: int > 0. Length of the window of the rolling mean on basal contour. Return ---------- organo : object of class AnnularSheet the organo mesh extracted from the data """ membrane_dic = extract_membranes(brightfield_path, threshold, blur) clockwise_centers = _star_convex_polynoms(dapi_path, membrane_dic, scp_model_path) inside_df = pd.DataFrame(membrane_dic["inside"], index=None) outside_df = pd.DataFrame(membrane_dic["outside"], index=None) inners = inside_df.rolling(rol_window_inside, min_periods=1).mean().values outers = outside_df.rolling(rol_window_outside, min_periods=1).mean().values nb_cells = len(clockwise_centers) org_center = membrane_dic["center_inside"] - np.full( 2, membrane_dic["img_shape"][0] / 2.0) inner_vs, outer_vs = get_bissecting_vertices(clockwise_centers, inners, outers, org_center) organo = generate_ring(nb_cells, membrane_dic["rIn"], membrane_dic["rOut"]) organo.vert_df.loc[organo.apical_verts, organo.coords] = ( inner_vs[::-1] - np.full(inner_vs.shape, org_center)) * 0.323 organo.vert_df.loc[organo.basal_verts, organo.coords] = ( outer_vs[::-1] - np.full(outer_vs.shape, org_center)) * 0.323 inners = (inners - np.full(inners.shape, org_center)) * 0.323 outers = (outers - np.full(outers.shape, org_center)) * 0.323 clockwise_centers = np.array(clockwise_centers) clockwise_centers -= np.full(outer_vs.shape, org_center) clockwise_centers *= 0.323 organo.settings["R_in"] *= 0.323 organo.settings["R_out"] *= 0.323 return organo, inners, outers, clockwise_centers