def test_bodies(): body = Sphere(name="sphere", clever=False) assert str(body) == "sphere" repr(body) assert np.allclose(body.geometric_center, (0, 0, 0)) body.add_translation_dof(name="Surge") body.add_translation_dof(name="Heave") # Extract faces body.extract_faces(np.where(body.mesh.faces_centers[:, 2] < 0)[0]) # Clipping body.keep_immersed_part(inplace=False) # Mirror of the dofs mirrored = body.mirrored(Plane(point=(1, 0, 0), normal=(1, 0, 0))) assert np.allclose(mirrored.geometric_center, np.array([2, 0, 0])) assert np.allclose(body.dofs['Surge'], -mirrored.dofs['Surge']) # Rotation of the dofs sideways = body.rotated(Axis(point=(0, 0, 0), vector=(0, 1, 0)), np.pi/2) assert np.allclose(sideways.dofs['Heave'][0], np.array([1, 0, 0])) upside_down = body.rotated(Axis(point=(0, 0, 0), vector=(0, 1, 0)), np.pi) assert np.allclose(body.dofs['Heave'], -upside_down.dofs['Heave']) # Copy of the body copy_of_body = body.copy(name="copy_of_sphere") copy_of_body.translate_x(10.0) copy_of_body.add_translation_dof(name="Heave") # Join bodies both = body.join_bodies(copy_of_body) assert set(both.dofs) == {'sphere__Surge', 'copy_of_sphere__Surge', 'sphere__Heave', 'copy_of_sphere__Heave'}
def __init__(self, mesh_slice: Union[Mesh, CollectionOfMeshes], axis: Axis = Oz_axis, nb_repetitions: int = 1, name=None): assert isinstance(mesh_slice, Mesh) or isinstance( mesh_slice, CollectionOfMeshes) assert isinstance(nb_repetitions, int) assert nb_repetitions >= 1 assert isinstance(axis, Axis) slices = [mesh_slice] for i in range(1, nb_repetitions + 1): slices.append( mesh_slice.rotated(axis, angle=2 * i * np.pi / (nb_repetitions + 1), name=f"rotation_{i}_of_{mesh_slice.name}")) super().__init__(slices, name=name) if not axis.is_parallel_to(Oz_axis): LOG.warning( f"{self.name} is an axi-symmetric mesh along a non vertical axis." ) self.axis = axis.copy() if self.name is not None: LOG.debug(f"New rotation symmetric mesh: {self.name}.") else: LOG.debug(f"New rotation symmetric mesh.")
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_plane_transformations(): # TRANSLATIONS translated_plane = xOz_Plane.translate(vector=(1, 0, 0), inplace=False) assert xOz_Plane is not translated_plane assert xOz_Plane == translated_plane assert yOz_Plane.translated_x(10).rotated_y(np.pi / 8).c == 10 translated_plane = xOz_Plane.translate(vector=(0, 1, 0), inplace=False) assert translated_plane.c == 1 assert np.all(translated_plane.normal == xOz_Plane.normal) # ROTATIONS rotated_plane = xOz_Plane.rotate(Oy_axis, angle=np.pi / 12, inplace=False) assert rotated_plane == xOz_Plane.rotated(Oy_axis, angle=np.pi / 12) assert xOz_Plane is not rotated_plane assert xOz_Plane == rotated_plane rotated_plane = xOz_Plane.rotate(Ox_axis, angle=np.pi / 2, inplace=False) assert rotated_plane == xOy_Plane # MIRRORED BY ITSELF plane = Plane(normal=(1, 0, 0), point=(0.3, 0.2, 0.6)) assert plane.mirrored(plane) != plane assert plane.mirrored(plane) == Plane(normal=(-1, 0, 0), point=(0.3, 0.2, 0.6)) flipped_plane = plane.rotate(Axis(point=plane.point, vector=(0, 1, 0)), np.pi) assert flipped_plane == plane.mirror(plane)
def _generate_mesh_using_symmetry(self, ntheta, nphi, clip_free_surface, mesh_name): if clip_free_surface: if self.geometric_center[2] < -self.radius: # fully immersed theta_max = np.pi elif self.geometric_center[2] < self.radius: theta_max = np.arccos(self.geometric_center[2] / self.radius) else: raise ValueError( "Impossible to mesh the immersed hull of a sphere completely out of the water" ) else: theta_max = np.pi theta = np.linspace(0.0, theta_max, ntheta + 1) points_on_a_meridian = (self.radius * np.stack( [np.sin(theta), np.zeros_like(theta), -np.cos(theta)], axis=1) + self.geometric_center) symmetry_axis = Axis(vector=[0, 0, 1], point=self.geometric_center) return AxialSymmetricMesh.from_profile(points_on_a_meridian, axis=symmetry_axis, nphi=nphi, name=mesh_name)
def from_profile(profile: Union[Callable, Iterable[float]], z_range: Iterable[float]=np.linspace(-5, 0, 20), axis: Axis=Oz_axis, nphi: int=20, name=None): """Return a floating body using the axial symmetry. The shape of the body can be defined either with a function defining the profile as [f(z), 0, z] for z in z_range. Alternatively, the profile can be defined as a list of points. The number of vertices along the vertical direction is len(z_range) in the first case and profile.shape[0] in the second case. Parameters ---------- profile : function(float → float) or array(N, 3) define the shape of the body either as a function or a list of points. z_range: array(N), optional used only if the profile is defined as a function. axis : Axis symmetry axis nphi : int, optional number of vertical slices forming the body name : str, optional name of the generated body (optional) Returns ------- AxialSymmetricMesh the generated mesh """ if name is None: name = "axisymmetric_mesh" if callable(profile): z_range = np.asarray(z_range) x_values = [profile(z) for z in z_range] profile_array = np.stack([x_values, np.zeros(len(z_range)), z_range]).T else: profile_array = np.asarray(profile) assert len(profile_array.shape) == 2 assert profile_array.shape[1] == 3 n = profile_array.shape[0] angle = 2 * np.pi / nphi nodes_slice = np.concatenate([profile_array, axis.rotate_points(profile_array, angle)]) faces_slice = np.array([[i, i+n, i+n+1, i+1] for i in range(n-1)]) body_slice = Mesh(nodes_slice, faces_slice, name=f"slice_of_{name}") body_slice.merge_duplicates() body_slice.heal_triangles() return AxialSymmetricMesh(body_slice, axis=axis, nb_repetitions=nphi - 1, name=name)
def fb_array(): sphere = Sphere( radius=r, # Dimension center=(0, 0, 0), # Position nphi=4, ntheta=10, # Fineness of the mesh ) my_axis = Axis((0, 1, 0), point=(0,0,0)) sphere.add_rotation_dof(axis=my_axis) sphere.keep_immersed_part() return sphere.assemble_arbitrary_array(locations)
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_axis(): assert np.allclose(Axis(vector=(1, 1, 1)).vector, np.sqrt(3)/3 * np.ones((3,))) assert Axis(vector=(1, 1, 1), point=(0, 0, 0)) == Axis(vector=(1, 1, 1), point=(2, 2, 2)) assert Axis(vector=(0, 0, 1), point=(0, 0, 0)) == Axis(vector=(2e-16, 3e-16, 1), point=(0, 0, 1.5)) assert Axis(vector=(1, 1, 1), point=(0, 0, 0)) != Axis(vector=(1, 1, 1), point=(2, 2, 0)) assert (2, 0, 0) in Ox_axis assert (0, 1, 0) not in Ox_axis assert Ox_axis.is_orthogonal_to(yOz_Plane) assert not Ox_axis.is_orthogonal_to((1, 1, 1)) assert Ox_axis.angle_with_respect_to(Oy_axis) == np.pi/2 assert Oy_axis.angle_with_respect_to(Ox_axis) == np.pi/2
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 rotate(self, axis: Axis, angle: float): self.translation = axis.rotation_matrix(angle) @ self.translation CollectionOfMeshes.rotate(self, axis, angle) return self
def test_rotation_non_reference_axis(): axis = Axis(vector=(0, 0, 1), point=(1, 0, 0)) point = [[1.0, 0.0, 0.0]] rotated_point = axis.rotate_points(point, np.pi) assert np.allclose(rotated_point, point)
def test_axis_transformation(): assert Ox_axis.translated_x(10) == Ox_axis assert Ox_axis.translated_y(10) == Axis(vector=(1, 0, 0), point=(0, 10, 0)) assert Ox_axis.rotated(Ox_axis, angle=np.pi / 2) == Ox_axis assert Ox_axis.rotated(Oy_axis, angle=-np.pi / 2) == Oz_axis assert Ox_axis.mirrored(plane=yOz_Plane) == Ox_axis assert Ox_axis.mirrored(plane=xOz_Plane.translated_y(2)) == Axis( vector=(1, 0, 0), point=(0, 4, 0)) axis1 = Axis(vector=(1, 1, 1), point=(0, 0, 0)) axis2 = Axis(vector=(1, 2, 3), point=(0, 0, 0)) assert axis1.rotated_around_center_to_align_vectors( axis1.point, axis1.vector, axis2.vector) == axis2 axis1.rotate(axis2, np.pi) assert axis1.rotated_around_center_to_align_vectors( axis1.point, axis1.vector, axis2.vector) == axis2 axis1.vector *= -1 assert axis1.rotated_around_center_to_align_vectors( axis1.point, axis1.vector, axis2.vector) == axis2 axis1 = Axis(vector=(1, 1, 1), point=(1, 2, 0)) axis2 = Axis(vector=(2, 2, 2), point=(0, 0, 0)) assert axis1.translated_point_to_point(axis1.point, axis2.point) == axis2
def rotate(self, axis: Axis, angle: float): self.translation = axis.rotate_vector([self.translation], angle)[0, :] CollectionOfMeshes.rotate(self, axis, angle) return self