library(acousticTS) test_that("Scatterer class inheritance works correctly", { # Test that all scatterer classes inherit from Scatterer # Create instances of each scatterer type # Test CAL (calibration sphere) - inherits from ELA cal_obj <- cal_generate() expect_s4_class(cal_obj, "CAL") expect_s4_class(cal_obj, "ELA") # CAL inherits from ELA expect_s4_class(cal_obj, "Scatterer") # ELA inherits from Scatterer expect_false(methods::is(cal_obj, "ESS")) # CAL is no longer treated as ESS # Test plain ELA solid target ela_obj <- ela_generate( shape = prolate_spheroid( length_body = 0.04, radius_body = 0.004, n_segments = 40 ), density_body = 14900, sound_speed_longitudinal_body = 6853, sound_speed_transversal_body = 4171 ) expect_s4_class(ela_obj, "ELA") expect_s4_class(ela_obj, "Scatterer") expect_false(methods::is(ela_obj, "CAL")) expect_false(methods::is(ela_obj, "ESS")) # Test ESS (elastic shelled sphere) ess_obj <- ess_generate(shape = sphere(radius_body = 1, n_segments = 80)) expect_s4_class(ess_obj, "ESS") expect_s4_class(ess_obj, "ELA") # ESS inherits from ELA expect_s4_class(ess_obj, "Scatterer") # ELA inherits from Scatterer # Test ESS where input is a pre-made shape ess_obj <- ess_generate(shape = sphere(radius_body = 1, n_segments = 80)) expect_s4_class(ess_obj, "ESS") expect_s4_class(ess_obj, "ELA") # ESS inherits from ELA expect_s4_class(ess_obj, "Scatterer") # ELA inherits from Scatterer # Test ESS where input is an arbitrary shape arb_shape <- cylinder(length_body = 1, radius_body = 0.2) ess_obj <- ess_generate(shape = arb_shape) expect_s4_class(ess_obj, "ESS") expect_s4_class(ess_obj, "ELA") # ESS inherits from ELA expect_s4_class(ess_obj, "Scatterer") # ELA inherits from Scatterer # Test GAS (gas-filled scatterer) gas_obj <- gas_generate(shape = sphere(radius_body = 1, n_segments = 80)) expect_s4_class(gas_obj, "GAS") expect_s4_class(gas_obj, "Scatterer") # GAS inherits from Scatterer # Test FLS (fluid-like scatterer) fls_obj <- fls_generate( x_body = c(1, 2), y_body = c(1, 2), z_body = c(1, 2), radius_body = c(1, 2), g_body = 1.00, h_body = 1.00 ) expect_s4_class(fls_obj, "FLS") expect_s4_class(fls_obj, "Scatterer") # FLS inherits from Scatterer # Test SBF (swimbladdered fish) - inherits from GAS # Create a simple SBF object for testing x_body <- seq(0, 0.1, length.out = 11) w_body <- rep(0.01, 11) zU_body <- rep(0.005, 11) zL_body <- rep(-0.005, 11) x_bladder <- seq(0.02, 0.08, length.out = 7) w_bladder <- rep(0.005, 7) zU_bladder <- rep(0.003, 7) zL_bladder <- rep(-0.003, 7) sbf_obj <- sbf_generate( x_body = x_body, w_body = w_body, zU_body = zU_body, zL_body = zL_body, x_bladder = x_bladder, w_bladder = w_bladder, zU_bladder = zU_bladder, zL_bladder = zL_bladder, sound_speed_body = 1570, sound_speed_bladder = 345, density_body = 1070, density_bladder = 1.24 ) expect_s4_class(sbf_obj, "SBF") expect_s4_class(sbf_obj, "GAS") # SBF inherits from GAS expect_s4_class(sbf_obj, "Scatterer") # GAS inherits from Scatterer # Test BBF (backboned fish) - inherits from CSC body_shape <- arbitrary( x_body = c(0, 0.05, 0.10), zU_body = c(0.001, 0.004, 0.001), zL_body = c(-0.001, -0.004, -0.001) ) backbone_shape <- cylinder( length_body = 0.06, radius_body = 0.0005, n_segments = 20 ) bbf_obj <- bbf_generate( body_shape = body_shape, backbone_shape = backbone_shape, density_body = 1070, sound_speed_body = 1570, density_backbone = 1900, sound_speed_longitudinal_backbone = 3500, sound_speed_transversal_backbone = 1700 ) expect_s4_class(bbf_obj, "BBF") expect_s4_class(bbf_obj, "CSC") expect_s4_class(bbf_obj, "Scatterer") }) test_that("Scatterer objects have required slots", { # Test that Scatterer base class has required slots cal_obj <- cal_generate() # Check that slots can be accessed metadata <- cal_obj@metadata model_params <- cal_obj@model_parameters expect_type(metadata, "list") expect_type(model_params, "list") # Test with different scatterer types gas_obj <- gas_generate(shape = sphere(radius_body = 1, n_segments = 80)) expect_true("metadata" %in% slotNames(gas_obj)) expect_true("model_parameters" %in% slotNames(gas_obj)) fls_obj <- fls_generate( x = 1, y = 1, z = 1, radius_body = 1, g_body = 1, h_body = 1 ) expect_true("metadata" %in% slotNames(fls_obj)) expect_true("model_parameters" %in% slotNames(fls_obj)) }) test_that("Scatterer generation functions work", { # Test cal_generate cal_obj <- cal_generate() expect_s4_class(cal_obj, "CAL") expect_equal(cal_obj@metadata$ID, "Calibration sphere") # Default ID # Test with custom ID cal_obj_custom <- cal_generate(ID = "TestSphere") expect_equal(cal_obj_custom@metadata$ID, "TestSphere") # Test ess_generate ess_obj <- ess_generate(shape = sphere(radius_body = 1, n_segments = 80)) expect_s4_class(ess_obj, "ESS") expect_equal(ess_obj@metadata$ID, "UID") # Test gas_generate gas_obj <- gas_generate(shape = sphere(radius_body = 1, n_segments = 80)) expect_s4_class(gas_obj, "GAS") expect_equal(gas_obj@metadata$ID, "UID") # Test fls_generate fls_obj <- fls_generate( x = 1, y = 1, z = 1, radius_body = 1, g_body = 1, h_body = 1 ) expect_s4_class(fls_obj, "FLS") expect_equal(fls_obj@metadata$ID, "UID") }) test_that("Scatterer objects have proper structure", { # Test CAL structure cal_obj <- cal_generate() expect_true("body" %in% slotNames(cal_obj)) expect_type(cal_obj@body, "list") # Test GAS structure gas_obj <- gas_generate(shape = sphere(radius_body = 1, n_segments = 80)) expect_true("body" %in% slotNames(gas_obj)) expect_type(gas_obj@body, "list") # Test FLS structure fls_obj <- fls_generate( x = 1, y = 1, z = 1, radius_body = 1, g_body = 1, h_body = 1 ) expect_true("body" %in% slotNames(fls_obj)) expect_type(fls_obj@body, "list") # SBF should have both body and bladder x_body <- seq(0, 0.05, length.out = 6) w_body <- rep(0.005, 6) zU_body <- rep(0.0025, 6) zL_body <- rep(-0.0025, 6) x_bladder <- seq(0.01, 0.04, length.out = 4) w_bladder <- rep(0.002, 4) zU_bladder <- rep(0.001, 4) zL_bladder <- rep(-0.001, 4) sbf_obj <- sbf_generate( x_body = x_body, w_body = w_body, zU_body = zU_body, zL_body = zL_body, x_bladder = x_bladder, w_bladder = w_bladder, zU_bladder = zU_bladder, zL_bladder = zL_bladder, sound_speed_body = 1570, sound_speed_bladder = 345, density_body = 1070, density_bladder = 1.24 ) expect_true("body" %in% slotNames(sbf_obj)) expect_true("bladder" %in% slotNames(sbf_obj)) expect_type(sbf_obj@body, "list") expect_type(sbf_obj@bladder, "list") }) test_that("CAL-class generation works as expected", { # Create object cal_sphere <- cal_generate( sound_speed_longitudinal = 3e3, sound_speed_transversal = 5e3, density_sphere = 1e3 ) # Extract mat_props <- acousticTS::extract(cal_sphere, "body") expect_equal(mat_props$sound_speed_longitudinal, 3e3) expect_equal(mat_props$sound_speed_transversal, 5e3) expect_equal(mat_props$density, 1e3) }) test_that("FLS-class generation works as expected", { # Test full parmeterization fls_test <- fls_generate( x_body = seq(0, 1, length.out = 5), y_body = rep(0, 5), z_body = rep(0, 5), radius_body = rep(0.5, 5), g_body = 1.01, h_body = 1.02, ID = "test" ) body <- acousticTS::extract(fls_test, "body") shape <- acousticTS::extract(fls_test, "shape_parameters") expect_equal(dim(body$rpos), c(6, 5)) expect_equal(length(body$radius), 5) # Test shape input tcyl <- cylinder( length_body = 0.5, radius_body = 0.1, taper = 10, n_segments = 4 ) fls_cyl <- fls_generate( shape = tcyl, g_body = 1.01, h_body = 1.02, ) body <- acousticTS::extract(fls_cyl, "body") shape <- acousticTS::extract(fls_cyl, "shape_parameters") expect_equal(dim(body$rpos), c(5, 5)) expect_equal(length(body$radius), 5) expect_equal(max(body$rpos[1, ]), 0.5) expect_equal(max(body$radius), max(tcyl@shape_parameters$radius)) expect_equal(shape$shape, "Cylinder") expect_equal(shape$length, 0.5) expect_equal(shape$radius, max(tcyl@shape_parameters$radius)) expect_equal(shape$taper_order, 10) # Test shape-first cylinder input fls_cyl <- fls_generate( shape = cylinder( length_body = 0.5, radius_body = 0.025, n_segments = 100 ), h_body = 1, g_body = 1 ) body <- acousticTS::extract(fls_cyl, "body") shape <- acousticTS::extract(fls_cyl, "shape_parameters") expect_equal(dim(body$rpos), c(5, 101)) expect_equal(length(body$radius), 101) expect_equal(max(body$rpos[1, ]), 0.5) expect_equal(max(body$radius), 0.025) expect_equal(shape$shape, "Cylinder") expect_equal(shape$length, 0.5) # Test sphere sph <- sphere(radius_body = 1) fls_sph <- fls_generate( shape = sph, g_body = 1, h_body = 1 ) body <- acousticTS::extract(fls_sph, "body") shape <- acousticTS::extract(fls_sph, "shape_parameters") expect_equal(dim(body$rpos), c(5, 101)) expect_equal(length(body$radius), 1) expect_equal(max(body$rpos[1, ]), 2) expect_equal(body$radius, 1) expect_equal(shape$shape, "Sphere") expect_equal(shape$length, 2) # Test inhomogenous g and h fls_gh <- fls_generate( x_body = seq(0, 1, length.out = 5), y_body = rep(0, 5), z_body = rep(0, 5), radius_body = 0.1, n_segments = 4, g_body = seq(1, 2, length.out = 4), h_body = seq(1, 2, length.out = 4) ) body <- acousticTS::extract(fls_gh, "body") expect_equal(length(body$g), 4) expect_equal(length(body$h), 4) # Test expected errors # ---- Case: Empty[x_body] expect_error( fls_generate(), paste0( "Supply 'shape' as a pre-built Shape object, or provide explicit ", "profile coordinates" ) ) # ---- Case: Different g count expect_error( fls_generate( x_body = seq(0, 1, length.out = 5), y_body = rep(0, 5), z_body = rep(0, 5), radius_body = 0.1, n_segments = 4, g_body = seq(1, 2, length.out = 5), h_body = 1 ), paste0( "Vector input for 'g_body' with 5 elements does not match the ", "expected number of segments \\(4\\)" ) ) # ---- Case: Different h count expect_error( fls_generate( x_body = seq(0, 1, length.out = 5), y_body = rep(0, 5), z_body = rep(0, 5), radius_body = 0.1, n_segments = 4, g_body = 1, h_body = seq(1, 2, length.out = 5) ), paste0( "Vector input for 'h_body' with 5 elements does not match the ", "expected number of segments \\(4\\)" ) ) }) test_that("ESS error cases are raised when necessary", { # Test case where conflicting density/g and sound speed/h values are input expect_error( ess_generate( shape = sphere(radius_body = 1, n_segments = 80), h_shell = 1, sound_speed_shell = 1700 ), "Cannot specify both h_shell and sound_speed_shell" ) expect_error( ess_generate( shape = sphere(radius_body = 1, n_segments = 80), g_shell = 1, density_shell = 1700 ), "Cannot specify both g_shell and density_shell" ) })