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_problems_from_dataset(): body = Sphere(center=(0, 0, -4), name="sphere") body.add_translation_dof(name="Heave") dset = xr.Dataset(coords={'omega': [0.5, 1.0, 1.5], 'radiating_dof': ["Heave"], 'body_name': ["sphere"], 'wave_direction': [0.0], 'water_depth': [np.infty]}) problems = problems_from_dataset(dset, [body]) assert RadiationProblem(body=body, omega=0.5, radiating_dof="Heave") in problems assert len(problems) == 6 assert len([problem for problem in problems if isinstance(problem, DiffractionProblem)]) == 3 dset = xr.Dataset(coords={'omega': [0.5, 1.0, 1.5], 'wave_direction': [0.0], 'body_name': ["cube"]}) with pytest.raises(AssertionError): problems_from_dataset(dset, [body]) shifted_body = body.translated_y(5.0, name="shifted_sphere") dset = xr.Dataset(coords={'omega': [0.5, 1.0, 1.5], 'radiating_dof': ["Heave"], 'wave_direction': [0.0]}) problems = problems_from_dataset(dset, [body, shifted_body]) assert RadiationProblem(body=body, omega=0.5, radiating_dof="Heave") in problems assert RadiationProblem(body=shifted_body, omega=0.5, radiating_dof="Heave") in problems assert len(problems) == 12
def test_floating_sphere_finite_depth(): """Compare with Nemoh 2.0 for some cases of a heaving sphere at the free surface in finite depth.""" sphere = Sphere(radius=1.0, ntheta=3, nphi=12, clip_free_surface=True) sphere.add_translation_dof(direction=(0, 0, 1), name="Heave") # omega = 1, radiation problem = RadiationProblem(body=sphere, omega=1.0, radiating_dof="Heave", sea_bottom=-10.0) result = solver.solve(problem, keep_details=True) assert np.isclose(result.added_masses["Heave"], 1740.6, atol=1e-3*sphere.volume*problem.rho) assert np.isclose(result.radiation_dampings["Heave"], 380.46, atol=1e-3*sphere.volume*problem.rho) kochin = compute_kochin(result, np.linspace(0, np.pi, 3)) assert np.allclose(kochin, np.roll(kochin, 1)) # The far field is the same in all directions. assert np.isclose(kochin[0], -0.2267+3.49e-3j, rtol=1e-3) # omega = 1, diffraction problem = DiffractionProblem(body=sphere, omega=1.0, wave_direction=0.0, sea_bottom=-10.0) result = solver.solve(problem) assert np.isclose(result.forces["Heave"], 1749.4 * np.exp(-2.922j), rtol=1e-3) # omega = 2, radiation problem = RadiationProblem(body=sphere, omega=2.0, radiating_dof="Heave", sea_bottom=-10.0) result = solver.solve(problem) assert np.isclose(result.added_masses["Heave"], 1375.0, atol=1e-3*sphere.volume*problem.rho) assert np.isclose(result.radiation_dampings["Heave"], 1418.0, atol=1e-3*sphere.volume*problem.rho) # omega = 2, diffraction problem = DiffractionProblem(body=sphere, omega=2.0, wave_direction=0.0, sea_bottom=-10.0) result = solver.solve(problem) assert np.isclose(result.forces["Heave"], 5872.8 * np.exp(-2.627j), rtol=1e-3)
def test_floating_sphere_finite_freq(): """Compare with Nemoh 2.0 for some cases of a heaving sphere at the free surface in infinite depth.""" sphere = Sphere(radius=1.0, ntheta=3, nphi=12, clip_free_surface=True) sphere.add_translation_dof(direction=(0, 0, 1), name="Heave") # omega = 1, radiation problem = RadiationProblem(body=sphere, omega=1.0, sea_bottom=-np.infty) result = solver.solve(problem, keep_details=True) assert np.isclose(result.added_masses["Heave"], 1819.6, atol=1e-3*sphere.volume*problem.rho) assert np.isclose(result.radiation_dampings["Heave"], 379.39, atol=1e-3*sphere.volume*problem.rho) # omega = 1, free surface free_surface = FreeSurface(x_range=(-62.5, 62.5), nx=5, y_range=(-62.5, 62.5), ny=5) eta = solver.get_free_surface_elevation(result, free_surface) ref = np.array( [[-0.4340802E-02-0.4742809E-03j, -0.7986111E-03+0.4840984E-02j, 0.2214827E-02+0.4700642E-02j, -0.7986111E-03+0.4840984E-02j, -0.4340803E-02-0.4742807E-03j], [-0.7986111E-03+0.4840984E-02j, 0.5733187E-02-0.2179381E-02j, 0.9460892E-03-0.7079404E-02j, 0.5733186E-02-0.2179381E-02j, -0.7986110E-03+0.4840984E-02j], [0.2214827E-02+0.4700643E-02j, 0.9460892E-03-0.7079403E-02j, -0.1381670E-01+0.6039315E-01j, 0.9460892E-03-0.7079405E-02j, 0.2214827E-02+0.4700643E-02j], [-0.7986111E-03+0.4840984E-02j, 0.5733186E-02-0.2179381E-02j, 0.9460891E-03-0.7079404E-02j, 0.5733187E-02-0.2179380E-02j, -0.7986113E-03+0.4840984E-02j], [-0.4340803E-02-0.4742807E-03j, -0.7986111E-03+0.4840984E-02j, 0.2214827E-02+0.4700643E-02j, -0.7986113E-03+0.4840983E-02j, -0.4340803E-02-0.4742809E-03j]] ) assert np.allclose(eta.reshape((5, 5)), ref, rtol=1e-4) # omega = 1, diffraction problem = DiffractionProblem(body=sphere, omega=1.0, sea_bottom=-np.infty) result = solver.solve(problem, keep_details=True) assert np.isclose(result.forces["Heave"], 1834.9 * np.exp(-2.933j), rtol=1e-3) # omega = 1, Kochin function of diffraction problem kochin = compute_kochin(result, np.linspace(0, np.pi, 10)) ref_kochin = np.array([ 0.20229*np.exp(-1.5872j), 0.20369*np.exp(-1.5871j), 0.20767*np.exp(-1.5868j), 0.21382*np.exp(-1.5863j), 0.22132*np.exp(-1.5857j), 0.22931*np.exp(-1.5852j), 0.23680*np.exp(-1.5847j), 0.24291*np.exp(-1.5843j), 0.24688*np.exp(-1.5841j), 0.24825*np.exp(-1.5840j), ]) assert np.allclose(kochin, ref_kochin, rtol=1e-3) # omega = 2, radiation problem = RadiationProblem(body=sphere, omega=2.0, sea_bottom=-np.infty) result = solver.solve(problem) assert np.isclose(result.added_masses["Heave"], 1369.3, atol=1e-3*sphere.volume*problem.rho) assert np.isclose(result.radiation_dampings["Heave"], 1425.6, atol=1e-3*sphere.volume*problem.rho) # omega = 2, diffraction problem = DiffractionProblem(body=sphere, omega=2.0, sea_bottom=-np.infty) result = solver.solve(problem) assert np.isclose(result.forces["Heave"], 5846.6 * np.exp(-2.623j), rtol=1e-3)
def test_limit_frequencies(): """Test if how the solver answers when asked for frequency of 0 or ∞.""" solver = Nemoh() solver.solve(RadiationProblem(body=sphere, omega=0.0, sea_bottom=-np.infty)) with pytest.raises(NotImplementedError): solver.solve(RadiationProblem(body=sphere, omega=0.0, sea_bottom=-1.0)) solver.solve( RadiationProblem(body=sphere, omega=np.infty, sea_bottom=-np.infty)) with pytest.raises(NotImplementedError): solver.solve( RadiationProblem(body=sphere, omega=np.infty, sea_bottom=-10))
def test_alien_sphere(): """Compare with Nemoh 2.0 for some cases of a heaving sphere at the free surface in infinite depth for a non-usual gravity and density.""" sphere = Sphere(radius=1.0, ntheta=3, nphi=12, clip_free_surface=True) sphere.add_translation_dof(direction=(0, 0, 1), name="Heave") sphere.add_translation_dof(direction=(1, 0, 0), name="Surge") # radiation problem = RadiationProblem(body=sphere, rho=450.0, g=1.625, omega=1.0, radiating_dof="Heave") result = solver.solve(problem) assert np.isclose(result.added_masses["Heave"], 515, atol=1e-3 * sphere.volume * problem.rho) assert np.isclose(result.radiation_dampings["Heave"], 309, atol=1e-3 * sphere.volume * problem.rho) # diffraction problem = DiffractionProblem(body=sphere, rho=450.0, g=1.625, omega=1.0, sea_bottom=-np.infty) result = solver.solve(problem) assert np.isclose(result.forces["Heave"], 548.5 * np.exp(-2.521j), rtol=1e-2)
def test_two_distant_spheres_in_finite_depth(): radius = 0.5 resolution = 4 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="buoy") other_buoy = buoy.translated_x(20, name="other_buoy") both_buoys = buoy.join_bodies(other_buoy) both_buoys.add_translation_dof(name="Surge") problem = RadiationProblem(body=both_buoys, radiating_dof="Surge", sea_bottom=-10, omega=7.0) result = solver.solve(problem) total_volume = 2 * 4 / 3 * np.pi * radius**3 assert np.isclose(result.added_masses['Surge'], 124.0, atol=1e-3 * total_volume * problem.rho) assert np.isclose(result.radiation_dampings['Surge'], 913.3, atol=1e-3 * total_volume * problem.rho)
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_array_of_spheres(): 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="Surge") buoy.add_translation_dof(name="Sway") buoy.add_translation_dof(name="Heave") # Corner case dumb_array = buoy.assemble_regular_array(distance=5.0, nb_bodies=(1, 1)) assert dumb_array.mesh == buoy.mesh # Main case array = buoy.assemble_regular_array(distance=4.0, nb_bodies=(3, 3)) assert isinstance(array.mesh, TranslationalSymmetricMesh) assert isinstance(array.mesh[0], TranslationalSymmetricMesh) assert array.mesh[0][0] == buoy.mesh assert len(array.dofs) == 3 * 3 * 3 assert "2_0__Heave" in array.dofs # array = buoy.assemble_regular_array(distance=4.0, nb_bodies=(3, 1)) settings = dict(cache_rankine_matrices=False, matrix_cache_size=0) nemoh_without_sym = Nemoh(hierarchical_matrices=False, **settings) nemoh_with_sym = Nemoh(hierarchical_matrices=True, **settings) fullS, fullV = nemoh_without_sym.build_matrices(array.mesh, array.mesh, 0.0, -np.infty, 1.0) S, V = nemoh_with_sym.build_matrices(array.mesh, array.mesh, 0.0, -np.infty, 1.0) assert isinstance(S, cpt.matrices.block.BlockMatrix) assert np.allclose(S.full_matrix(), fullS) assert np.allclose(V.full_matrix(), fullV) problem = RadiationProblem(body=array, omega=1.0, radiating_dof="2_0__Heave", sea_bottom=-np.infty) result = nemoh_with_sym.solve(problem) result2 = nemoh_without_sym.solve(problem) assert np.isclose(result.added_masses['2_0__Heave'], result2.added_masses['2_0__Heave'], atol=15.0) assert np.isclose(result.radiation_dampings['2_0__Heave'], result2.radiation_dampings['2_0__Heave'], atol=15.0)
def test_immersed_sphere(): """Compare with Nemoh 2.0 for a sphere in infinite fluid. The test is ran for two degrees of freedom; due to the symmetries of the problem, the results should be the same. They are actually slightly different due to the meshing of the sphere. """ sphere = Sphere(radius=1.0, ntheta=10, nphi=40, clip_free_surface=False) sphere.add_translation_dof(direction=(1, 0, 0), name="Surge") sphere.add_translation_dof(direction=(0, 0, 1), name="Heave") problem = RadiationProblem(body=sphere, radiating_dof="Heave", free_surface=np.infty, sea_bottom=-np.infty) result = solver.solve(problem) assert np.isclose(result.added_masses["Heave"], 2187, atol=1e-3 * sphere.volume * problem.rho) assert np.isclose(result.added_masses["Surge"], 0.0, atol=1e-3 * sphere.volume * problem.rho) assert np.isclose(result.radiation_dampings["Heave"], 0.0, atol=1e-3 * sphere.volume * problem.rho) assert np.isclose(result.radiation_dampings["Surge"], 0.0, atol=1e-3 * sphere.volume * problem.rho) problem = RadiationProblem(body=sphere, radiating_dof="Surge", free_surface=np.infty, sea_bottom=-np.infty) result = solver.solve(problem) assert np.isclose(result.added_masses["Surge"], 2194, atol=1e-3 * sphere.volume * problem.rho) assert np.isclose(result.added_masses["Heave"], 0.0, atol=1e-3 * sphere.volume * problem.rho) assert np.isclose(result.radiation_dampings["Surge"], 0.0, atol=1e-3 * sphere.volume * problem.rho) assert np.isclose(result.radiation_dampings["Heave"], 0.0, atol=1e-3 * sphere.volume * problem.rho)
def problems_from_dataset(dataset: xr.Dataset, bodies: Sequence[FloatingBody], ) -> List[LinearPotentialFlowProblem]: """Generate a list of problems from a test matrix. Parameters ---------- dataset : xarray Dataset Test matrix containing the problems parameters. bodies : list of FloatingBody The bodies on which the computations of the test matrix will be applied. They should all have different names. Returns ------- list of LinearPotentialFlowProblem """ assert len(list(set(body.name for body in bodies))) == len(bodies), \ "All bodies should have different names." dataset = _unsqueeze_dimensions(dataset) omega_range = dataset['omega'].data if 'omega' in dataset else [_default_parameters['omega']] water_depth_range = dataset['water_depth'].data if 'water_depth' in dataset else [_default_parameters['water_depth']] rho_range = dataset['rho'].data if 'rho' in dataset else [_default_parameters['rho']] wave_direction_range = dataset['wave_direction'].data if 'wave_direction' in dataset else None radiating_dofs = dataset['radiating_dof'].data.astype(object) if 'radiating_dof' in dataset else None # astype(object) is meant to convert Numpy internal string type numpy.str_ to Python general string type. if 'body_name' in dataset: assert set(dataset['body_name'].data) <= {body.name for body in bodies}, \ "Some body named in the dataset was not given as argument to `problems_from_dataset`." body_range = {body.name: body for body in bodies if body.name in dataset['body_name'].data} # Only the bodies listed in the dataset have been kept else: body_range = {body.name: body for body in bodies} problems = [] if wave_direction_range is not None: for omega, wave_direction, water_depth, body_name, rho \ in product(omega_range, wave_direction_range, water_depth_range, body_range, rho_range): problems.append( DiffractionProblem(body=body_range[body_name], omega=omega, wave_direction=wave_direction, sea_bottom=-water_depth, rho=rho) ) if radiating_dofs is not None: for omega, radiating_dof, water_depth, body_name, rho \ in product(omega_range, radiating_dofs, water_depth_range, body_range, rho_range): problems.append( RadiationProblem(body=body_range[body_name], omega=omega, radiating_dof=radiating_dof, sea_bottom=-water_depth, rho=rho) ) return sorted(problems)
def test_multibody(): """Compare with Nemoh 2.0 for two bodies.""" sphere = Sphere(radius=1.0, ntheta=5, nphi=20) sphere.translate_z(-2.0) sphere.add_translation_dof(direction=(1, 0, 0), name="Surge") sphere.add_translation_dof(direction=(0, 0, 1), name="Heave") cylinder = HorizontalCylinder(length=5.0, radius=1.0, nx=10, nr=1, ntheta=10) cylinder.translate([+1.5, 3.0, -3.0]) cylinder.add_translation_dof(direction=(1, 0, 0), name="Surge") cylinder.add_translation_dof(direction=(0, 0, 1), name="Heave") both = cylinder + sphere total_volume = cylinder.volume + sphere.volume # both.show() problems = [ RadiationProblem(body=both, radiating_dof=dof, omega=1.0) for dof in both.dofs ] problems += [DiffractionProblem(body=both, wave_direction=0.0, omega=1.0)] results = [solver.solve(problem) for problem in problems] data = assemble_dataset(results) data_from_nemoh_2 = np.array([ [ 3961.86548, 50.0367661, -3.32347107, 6.36901855E-02, 172.704819, 19.2018471, -5.67303181, -2.98873377 ], [ -3.08301544, 5.72392941E-02, 14522.1689, 271.796814, 128.413834, 6.03351116, 427.167358, 64.1587067 ], [ 161.125534, 17.8332844, 126.392113, 5.88006783, 2242.47412, 7.17850924, 1.29002571, 0.393169671 ], [ -5.02560759, -2.75930357, 419.927460, 63.3179016, 1.23501396, 0.416424811, 2341.57593, 15.8266096 ], ]) dofs_names = list(both.dofs.keys()) assert np.allclose(data['added_mass'].sel( omega=1.0, radiating_dof=dofs_names, influenced_dof=dofs_names).values, data_from_nemoh_2[:, ::2], atol=1e-3 * total_volume * problems[0].rho) assert np.allclose(data['radiation_damping'].sel( omega=1.0, radiating_dof=dofs_names, influenced_dof=dofs_names).values, data_from_nemoh_2[:, 1::2], atol=1e-3 * total_volume * problems[0].rho)
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_results(): assert isinstance(LinearPotentialFlowProblem().make_results_container(), LinearPotentialFlowResult) pb = DiffractionProblem(g=10, rho=1023, free_surface=np.infty) res = DiffractionResult(pb) assert res.g == pb.g == 10 assert "DiffractionResult" in str(res) pb = RadiationProblem(g=10, rho=1023, free_surface=np.infty) res = RadiationResult(pb) assert res.g == pb.g == 10 assert "RadiationResult" in str(res)
def test_radiation_problem(caplog): sphere = Sphere(radius=1.0, ntheta=20, nphi=40, clip_free_surface=True) # with pytest.raises(ValueError): # RadiationProblem(body=sphere) sphere.add_translation_dof(direction=(0, 0, 1), name="Heave") pb = RadiationProblem(body=sphere) assert len(pb.boundary_condition) == sphere.mesh.nb_faces sphere.add_translation_dof(direction=(1, 0, 0), name="Surge") pb2 = RadiationProblem(body=sphere, radiating_dof="Heave") assert np.all(pb.boundary_condition == pb2.boundary_condition) assert "RadiationProblem" in str(RadiationProblem(g=10, rho=1025, free_surface=np.infty)) res = pb.make_results_container() assert isinstance(res, RadiationResult) assert 'forces' not in res.__dict__ assert res.added_masses == {} assert res.radiation_dampings == {}
def test_horizontal_cylinder(depth): cylinder = HorizontalCylinder(length=10.0, radius=1.0, reflection_symmetry=False, translation_symmetry=False, nr=2, ntheta=10, nx=10) assert isinstance(cylinder.mesh, Mesh) cylinder.translate_z(-3.0) cylinder.add_translation_dof(direction=(0, 0, 1), name="Heave") problem = RadiationProblem(body=cylinder, omega=1.0, sea_bottom=-depth) result1 = solver_with_sym.solve(problem) trans_cylinder = HorizontalCylinder(length=10.0, radius=1.0, reflection_symmetry=False, translation_symmetry=True, nr=2, ntheta=10, nx=10) assert isinstance(trans_cylinder.mesh, CollectionOfMeshes) assert isinstance(trans_cylinder.mesh[0], TranslationalSymmetricMesh) trans_cylinder.translate_z(-3.0) trans_cylinder.add_translation_dof(direction=(0, 0, 1), name="Heave") problem = RadiationProblem(body=trans_cylinder, omega=1.0, sea_bottom=-depth) result2 = solver_with_sym.solve(problem) # S, V = solver_with_sym.build_matrices(trans_cylinder.mesh, trans_cylinder.mesh) # S.plot_shape() assert np.isclose(result1.added_masses["Heave"], result2.added_masses["Heave"], atol=1e-4*cylinder.volume*problem.rho) assert np.isclose(result1.radiation_dampings["Heave"], result2.radiation_dampings["Heave"], atol=1e-4*cylinder.volume*problem.rho)
def test_assemble_dataset(): body = Sphere(center=(0, 0, -4), name="sphere") body.add_translation_dof(name="Heave") pb_1 = DiffractionProblem(body=body, wave_direction=1.0, omega=1.0) res_1 = solver.solve(pb_1) ds1 = assemble_dataset([res_1]) assert "Froude_Krylov_force" in ds1 pb_2 = RadiationProblem(body=body, radiating_dof="Heave", omega=1.0) res_2 = solver.solve(pb_2) ds2 = assemble_dataset([res_2]) assert "added_mass" in ds2 ds12 = assemble_dataset([res_1, res_2]) assert "Froude_Krylov_force" in ds12 assert "added_mass" in ds12
def test_custom_linear_solver(): """Solve a simple problem with a custom linear solver.""" problem = RadiationProblem(body=sphere, omega=1.0, sea_bottom=-np.infty) reference_solver = BEMSolver( engine=BasicMatrixEngine(linear_solver="gmres", matrix_cache_size=0)) reference_result = reference_solver.solve(problem) def my_linear_solver(A, b): """A dumb solver for testing.""" return np.linalg.inv(A) @ b my_bem_solver = BEMSolver(engine=BasicMatrixEngine( linear_solver=my_linear_solver, matrix_cache_size=0)) assert 'my_linear_solver' in my_bem_solver.exportable_settings[ 'linear_solver'] result = my_bem_solver.solve(problem) assert np.isclose(reference_result.added_masses['Surge'], result.added_masses['Surge'])
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 _ in range(nb_bodies): cal_file.readline() # Unused line. mesh_file = cal_file.readline().split()[0].strip() mesh_file = os.path.join( os.path.dirname(filepath), mesh_file) # mesh path are relative to Nemoh.cal cal_file.readline() # Number of points, number of panels (unused) if os.path.splitext(mesh_file)[1] == '.py': from importlib.util import spec_from_file_location, module_from_spec spec = spec_from_file_location("body_initialization_module", mesh_file) body_initialization = module_from_spec(spec) spec.loader.exec_module(body_initialization) body = body_initialization.body else: body = FloatingBody.from_file(mesh_file) 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(vector=direction, 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 generalized 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) if nb_bodies > 1: bodies = FloatingBody.join_bodies(*bodies) else: bodies = bodies[0] 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])) direction_range = np.pi / 180 * direction_range # conversion from degrees to radians. # 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(wave_direction=direction, omega=omega, **env_args)) for dof in bodies.dofs: problems.append( RadiationProblem(radiating_dof=dof, omega=omega, **env_args)) return problems
def problems_from_dataset(dataset: xr.Dataset, bodies: Union[FloatingBody, Sequence[FloatingBody]], ) -> List[LinearPotentialFlowProblem]: """Generate a list of problems from a test matrix. Parameters ---------- dataset : xarray Dataset Test matrix containing the problems parameters. bodies : FloatingBody or list of FloatingBody The bodies on which the computations of the test matrix will be applied. They should all have different names. Returns ------- list of LinearPotentialFlowProblem Raises ------ ValueError if required fields are missing in the dataset """ if isinstance(bodies, FloatingBody): bodies = [bodies] # SANITY CHECKS assert len(list(set(body.name for body in bodies))) == len(bodies), \ "All bodies should have different names." # Warn user in case of key with unrecognized name (e.g. mispells) keys_in_dataset = set(dataset.keys()) | set(dataset.coords.keys()) accepted_keys = {'wave_direction', 'radiating_dof', 'body_name', 'omega', 'water_depth', 'rho', 'g'} unrecognized_keys = keys_in_dataset.difference(accepted_keys) if len(unrecognized_keys) > 0: LOG.warning(f"Unrecognized key(s) in dataset: {unrecognized_keys}") if ("radiating_dof" not in keys_in_dataset) and ("wave_direction" not in keys_in_dataset): raise ValueError("Neither 'radiating_dof' nor 'wave_direction' has been provided in the dataset. " "No linear potential flow problem can be inferred.") # END SANITY CHECKS dataset = _unsqueeze_dimensions(dataset) omega_range = dataset['omega'].data if 'omega' in dataset else [_default_parameters['omega']] water_depth_range = dataset['water_depth'].data if 'water_depth' in dataset else [_default_parameters['water_depth']] rho_range = dataset['rho'].data if 'rho' in dataset else [_default_parameters['rho']] g_range = dataset['g'].data if 'g' in dataset else [_default_parameters['g']] wave_direction_range = dataset['wave_direction'].data if 'wave_direction' in dataset else None radiating_dofs = dataset['radiating_dof'].data.astype(object) if 'radiating_dof' in dataset else None # astype(object) is meant to convert Numpy internal string type numpy.str_ to Python general string type. if 'body_name' in dataset: assert set(dataset['body_name'].data) <= {body.name for body in bodies}, \ "Some body named in the dataset was not given as argument to `problems_from_dataset`." body_range = {body.name: body for body in bodies if body.name in dataset['body_name'].data} # Only the bodies listed in the dataset have been kept else: body_range = {body.name: body for body in bodies} problems = [] if wave_direction_range is not None: for omega, wave_direction, water_depth, body_name, rho, g \ in product(omega_range, wave_direction_range, water_depth_range, body_range, rho_range, g_range): problems.append( DiffractionProblem(body=body_range[body_name], omega=omega, wave_direction=wave_direction, sea_bottom=-water_depth, rho=rho, g=g) ) if radiating_dofs is not None: for omega, radiating_dof, water_depth, body_name, rho, g \ in product(omega_range, radiating_dofs, water_depth_range, body_range, rho_range, g_range): problems.append( RadiationProblem(body=body_range[body_name], omega=omega, radiating_dof=radiating_dof, sea_bottom=-water_depth, rho=rho, g=g) ) return sorted(problems)