def test_dof(): nodes = np.array([[0, 0, 0], [0, 0, 1], [1, 0, 1], [1, 0, 0]]) faces = np.array([[0, 1, 2, 3]]) body = FloatingBody(Mesh(nodes, faces), name="one_face") assert body.dofs == {} body.add_translation_dof(direction=(1.0, 0.0, 0.0), name="1") assert np.allclose(body.dofs["1"], np.array([1.0, 0.0, 0.0])) body.add_translation_dof(direction=(0.0, 1.0, 0.0), name="2") assert np.allclose(body.dofs["2"], np.array([0.0, 1.0, 0.0])) body.add_rotation_dof(Axis(vector=(0.0, 0.0, 1.0)), name="3") body.add_rotation_dof(Axis(point=(0.5, 0, 0), vector=(0.0, 0.0, 1.0)), name="4")
def test_odd_axial_symmetry(): """Buoy with odd number of slices.""" def shape(z): return 0.1 * (-(z + 1)**2 + 16) buoy = FloatingBody( AxialSymmetricMesh.from_profile(shape, z_range=np.linspace(-5.0, 0.0, 9), nphi=5)) buoy.add_translation_dof(direction=(0, 0, 1), name="Heave") problem = RadiationProblem(body=buoy, omega=2.0) result1 = solver_with_sym.solve(problem) full_buoy = FloatingBody(buoy.mesh.merged()) full_buoy.add_translation_dof(direction=(0, 0, 1), name="Heave") problem = RadiationProblem(body=full_buoy, omega=2.0) result2 = solver_with_sym.solve(problem) volume = buoy.mesh.volume assert np.isclose(result1.added_masses["Heave"], result2.added_masses["Heave"], atol=1e-4 * volume * problem.rho) assert np.isclose(result1.radiation_dampings["Heave"], result2.radiation_dampings["Heave"], atol=1e-4 * volume * problem.rho)
def test_clipping_of_dofs(z_center, collection_of_meshes): """Check that clipping a body with a dof is the same as clipping the body ant then adding the dof.""" full_sphere = Sphere(center=(0, 0, z_center), name="sphere", clever=collection_of_meshes, clip_free_surface=False) axis = Axis(point=(1, 0, 0), vector=(1, 0, 0)) full_sphere.add_rotation_dof(axis, name="test_dof") clipped_sphere = full_sphere.keep_immersed_part(free_surface=0.0, sea_bottom=-np.infty, inplace=False) other_clipped_sphere = FloatingBody(mesh=clipped_sphere.mesh, name="other_sphere") other_clipped_sphere.add_rotation_dof(axis, name="test_dof") if clipped_sphere.mesh.nb_faces > 0: assert np.allclose(clipped_sphere.dofs['test_dof'], other_clipped_sphere.dofs['test_dof']) else: assert len(clipped_sphere.dofs['test_dof']) == 0
def test_low_rank_matrices(): radius = 1.0 resolution = 2 perimeter = 2 * np.pi * radius buoy = Sphere(radius=radius, center=(0.0, 0.0, 0.0), ntheta=int(perimeter * resolution / 2), nphi=int(perimeter * resolution), clip_free_surface=True, clever=False, name=f"buoy") buoy.add_translation_dof(name="Heave") two_distant_buoys = FloatingBody.join_bodies(buoy, buoy.translated_x(20)) two_distant_buoys.mesh._meshes[1].name = "other_buoy_mesh" S, V = solver_with_sym.build_matrices(two_distant_buoys.mesh, two_distant_buoys.mesh) assert isinstance(S.all_blocks[0, 1], LowRankMatrix) assert isinstance(S.all_blocks[1, 0], LowRankMatrix) # S.plot_shape() problem = RadiationProblem(body=two_distant_buoys, omega=1.0, radiating_dof="buoy__Heave") result = solver_with_sym.solve(problem) result2 = solver_without_sym.solve(problem) assert np.isclose(result.added_masses['buoy__Heave'], result2.added_masses['buoy__Heave'], atol=10.0) assert np.isclose(result.radiation_dampings['buoy__Heave'], result2.radiation_dampings['buoy__Heave'], atol=10.0)
def test_LinearPotentialFlowProblem(): # Without a body pb = LinearPotentialFlowProblem(omega=1.0) assert pb.omega == 1.0 assert pb.period == 2 * np.pi assert pb.wavenumber == 1.0 / 9.81 assert pb.wavelength == 9.81 * 2 * np.pi assert LinearPotentialFlowProblem(free_surface=np.infty, sea_bottom=-np.infty).depth == np.infty assert LinearPotentialFlowProblem(free_surface=0.0, sea_bottom=-np.infty).depth == np.infty pb = LinearPotentialFlowProblem(free_surface=0.0, sea_bottom=-1.0, omega=1.0) assert pb.depth == 1.0 assert np.isclose(pb.omega**2, pb.g * pb.wavenumber * np.tanh(pb.wavenumber * pb.depth)) assert pb.dimensionless_wavenumber == pb.wavenumber * 1.0 with pytest.raises(NotImplementedError): LinearPotentialFlowProblem(free_surface=2.0) with pytest.raises(NotImplementedError): LinearPotentialFlowProblem(free_surface=np.infty, sea_bottom=0.0) with pytest.raises(ValueError): LinearPotentialFlowProblem(free_surface=0.0, sea_bottom=1.0) with pytest.raises(TypeError): LinearPotentialFlowProblem(wave_direction=1.0) with pytest.raises(TypeError): LinearPotentialFlowProblem(radiating_dof="Heave") with pytest.raises(ValueError): LinearPotentialFlowProblem(body=FloatingBody(mesh=Mesh([], []))) # With a body sphere = Sphere(center=(0, 0, -2.0)) sphere.add_translation_dof(direction=(0, 0, 1), name="Heave") pb = LinearPotentialFlowProblem(body=sphere, omega=1.0) pb.boundary_condition = sphere.mesh.faces_normals @ (1, 1, 1) assert list(pb.influenced_dofs.keys()) == ['Heave'] pb2 = LinearPotentialFlowProblem(body=sphere, omega=2.0) pb2.boundary_condition = sphere.mesh.faces_normals @ (1, 1, 1) assert pb < pb2 # Test transformation to result class res = pb.make_results_container() assert isinstance(res, LinearPotentialFlowResult) assert res.problem is pb assert res.omega == pb.omega assert res.period == pb.period assert res.body is pb.body
def test_floating_sphere(depth, omega): """Comparison of the added mass and radiation damping for a heaving sphere described using several symmetries in finite and infinite depth. """ reso = 2 full_sphere = Sphere(radius=1.0, ntheta=reso, nphi=4*reso, axial_symmetry=False, clip_free_surface=True) full_sphere.add_translation_dof(direction=(0, 0, 1), name="Heave") problem = RadiationProblem(body=full_sphere, omega=omega, sea_bottom=-depth) result1 = solver_with_sym.solve(problem) half_sphere_mesh = full_sphere.mesh.extract_faces( np.where(full_sphere.mesh.faces_centers[:, 1] > 0)[0], name="half_sphere_mesh") two_halves_sphere = FloatingBody(ReflectionSymmetricMesh(half_sphere_mesh, xOz_Plane)) two_halves_sphere.add_translation_dof(direction=(0, 0, 1), name="Heave") problem = RadiationProblem(body=two_halves_sphere, omega=omega, sea_bottom=-depth) result2 = solver_with_sym.solve(problem) quarter_sphere_mesh = half_sphere_mesh.extract_faces( np.where(half_sphere_mesh.faces_centers[:, 0] > 0)[0], name="quarter_sphere_mesh") four_quarter_sphere = FloatingBody(ReflectionSymmetricMesh(ReflectionSymmetricMesh(quarter_sphere_mesh, yOz_Plane), xOz_Plane)) assert 'None' not in four_quarter_sphere.mesh.tree_view() four_quarter_sphere.add_translation_dof(direction=(0, 0, 1), name="Heave") problem = RadiationProblem(body=four_quarter_sphere, omega=omega, sea_bottom=-depth) result3 = solver_with_sym.solve(problem) clever_sphere = Sphere(radius=1.0, ntheta=reso, nphi=4*reso, axial_symmetry=True, clip_free_surface=True) clever_sphere.add_translation_dof(direction=(0, 0, 1), name="Heave") problem = RadiationProblem(body=clever_sphere, omega=omega, sea_bottom=-depth) result4 = solver_with_sym.solve(problem) # (quarter_sphere + half_sphere + full_sphere + clever_sphere).show() volume = 4/3*np.pi assert np.isclose(result1.added_masses["Heave"], result2.added_masses["Heave"], atol=1e-4*volume*problem.rho) assert np.isclose(result1.added_masses["Heave"], result3.added_masses["Heave"], atol=1e-4*volume*problem.rho) assert np.isclose(result1.added_masses["Heave"], result4.added_masses["Heave"], atol=1e-4*volume*problem.rho) assert np.isclose(result1.radiation_dampings["Heave"], result2.radiation_dampings["Heave"], atol=1e-4*volume*problem.rho) assert np.isclose(result1.radiation_dampings["Heave"], result3.radiation_dampings["Heave"], atol=1e-4*volume*problem.rho) assert np.isclose(result1.radiation_dampings["Heave"], result4.radiation_dampings["Heave"], atol=1e-4*volume*problem.rho)
def test_two_vertical_cylinders(): distance = 5 buoy = VerticalCylinder(length=3, radius=0.5, center=(-distance / 2, -1, 0), nx=8, nr=3, ntheta=8) buoy.mesh = buoy.mesh.merged() buoy.mesh = buoy.mesh.keep_immersed_part() buoy.add_translation_dof(name="Sway") two_buoys = FloatingBody.join_bodies(buoy, buoy.translated_x(distance)) two_buoys.mesh = buoy.mesh.symmetrized( yOz_Plane) # Use a ReflectionSymmetry as mesh... problems = [ RadiationProblem(body=two_buoys, omega=1.0, radiating_dof=dof) for dof in two_buoys.dofs ] results = assemble_dataset(solver_without_sym.solve_all(problems)) # Check that the resulting matrix is symmetric assert np.isclose(results['added_mass'].data[0, 0, 0], results['added_mass'].data[0, 1, 1]) assert np.isclose(results['added_mass'].data[0, 1, 0], results['added_mass'].data[0, 0, 1]) assert np.isclose(results['radiation_damping'].data[0, 0, 0], results['radiation_damping'].data[0, 1, 1]) assert np.isclose(results['radiation_damping'].data[0, 1, 0], results['radiation_damping'].data[0, 0, 1]) results_with_sym = assemble_dataset(solver_with_sym.solve_all(problems)) assert np.allclose(results['added_mass'].data, results_with_sym['added_mass'].data) assert np.allclose(results['radiation_damping'].data, results_with_sym['radiation_damping'].data)
def import_cal_file(filepath): """ Read a Nemoh.cal file and return a list of problems. """ with open(filepath, 'r') as cal_file: cal_file.readline() # Unused line. rho = float(cal_file.readline().split()[0]) g = float(cal_file.readline().split()[0]) depth = float(cal_file.readline().split()[0]) if depth == 0.0: sea_bottom = -np.infty else: sea_bottom = -depth xeff, yeff = (float(x) for x in cal_file.readline().split()[0:2]) bodies = [] cal_file.readline() # Unused line. nb_bodies = int(cal_file.readline().split()[0]) for i_body in range(nb_bodies): cal_file.readline() # Unused line. mesh_file = cal_file.readline().split()[0].strip() cal_file.readline() # Number of points, number of panels (unused) body = FloatingBody.from_file( os.path.join(os.path.dirname(filepath), mesh_file), # mesh path are relative to Nemoh.cal 'mar') nb_dofs = int(cal_file.readline().split()[0]) for i_dof in range(nb_dofs): dof_data = cal_file.readline().split() if int(dof_data[0]) == 1: direction = np.array([float(x) for x in dof_data[1:4]]) body.add_translation_dof(direction=direction) elif int(dof_data[0]) == 2: direction = np.array([float(x) for x in dof_data[1:4]]) center_of_mass = np.array([float(x) for x in dof_data[4:7]]) body.add_rotation_dof(axis_direction=direction, axis_point=center_of_mass) nb_forces = int(cal_file.readline().split()[0]) for i_force in range(nb_forces): force_data = cal_file.readline().split() if int(force_data[0]) == 1: direction = np.array([float(x) for x in force_data[1:4]]) elif int(force_data[0]) == 2: direction = np.array([float(x) for x in force_data[1:4]]) center_of_mass = np.array([float(x) for x in force_data[4:7]]) # TODO: use the generalize forces. nb_additional_lines = int(cal_file.readline().split()[0]) for _ in range(nb_additional_lines): cal_file.readline() # The additional lines are just ignored. bodies.append(body) bodies = CollectionOfFloatingBodies(bodies) cal_file.readline() # Unused line. frequency_data = cal_file.readline().split() omega_range = np.linspace(float(frequency_data[1]), float(frequency_data[2]), int(frequency_data[0])) direction_data = cal_file.readline().split() direction_range = np.linspace(float(direction_data[1]), float(direction_data[2]), int(direction_data[0])) # The options below are not implemented yet. cal_file.readline() # Unused line. irf_data = cal_file.readline() show_pressure = cal_file.readline().split()[0] == "1" kochin_data = cal_file.readline().split() kochin_range = np.linspace(float(kochin_data[1]), float(kochin_data[2]), int(kochin_data[0])) free_surface_data = cal_file.readline().split() # Generate Capytaine's problem objects env_args = dict(body=bodies, rho=rho, sea_bottom=sea_bottom, g=g) problems = [] for omega in omega_range: for direction in direction_range: problems.append(DiffractionProblem(angle=direction, omega=omega, **env_args)) if bodies.nb_dofs > 0: problems.append(RadiationProblem(omega=omega, **env_args)) return problems