/*
 * small_concert_hall.java
 */

import com.comsol.model.*;
import com.comsol.model.util.*;

/** Model exported on May 12 2026, 12:32 by COMSOL 6.4.0.418. */
public class small_concert_hall {

  public static Model run() {
    Model model = ModelUtil.create("Model");

//    From the File menu, choose New.
//    In the New window, click Model Wizard.
//    In the Model Wizard window, click 3D.
//    In the Select Physics tree, select Acoustics > Geometrical Acoustics > Ray Acoustics (rac).
//    Click Add.
//    Click Study.
//    In the Select Study tree, select Preset Studies for Selected Physics Interfaces > Ray Tracing.
//    Click Done.

    model.component().create("comp1", true);

    model.component("comp1").geom().create("geom1", 3);
    model.component("comp1").geom("geom1").geomRep("comsol");

    model.component("comp1").mesh().create("mesh1");
    model.component("comp1").mesh("mesh1").contribute("geom/detail", true);

    model.component("comp1").physics().create("rac", "RayAcoustics", "geom1");

    model.study().create("std1");
    model.study("std1").create("rtrac", "RayTracing");

//    The geometry is set up by importing a geometry sequence. The sequence imports the small concert hall geometry and sets up several selections. The predefined selections simplify the rest of the model setup.
//    In the Geometry toolbar, click Insert Sequence and choose Insert Sequence.

    model.component("comp1").geom("geom1").insertFile("small_concert_hall_geom_sequence.mph", "geom1");

//    Browse to the model's Application Library folder and double-click the file small_concert_hall_geom_sequence.mph.
//    In the Geometry toolbar, click Build All.

    model.component("comp1").geom("geom1").run("fin");

//    Click the Wireframe Rendering button in the Graphics toolbar.

    model.component("comp1").view("view1").set("renderwireframe", true);

//    Click the Zoom Extents button in the Graphics toolbar.
//    In the Model Builder window, under Component 1 (comp1), click Geometry 1.
//    Import the model parameters from the files. The parameters include the band center frequency <c>f0</c>, the location of the source and receiver, as well as the room volume.
//    In the Model Builder window, under Global Definitions, click Parameters 1.
//    In the Settings window for Parameters, type Parameters 1 - Model in the Label text field.

    model.param().label("Parameters 1 - Model");

//    Locate the Parameters section.
//    Click Load from File.
//    Browse to the model's Application Library folder and double-click the file small_concert_hall_parameters_model.txt.
//    To import content from file, use:
//    model.param().loadFile("FILENAME");
    model.param().set("f0", "500[Hz]", "Band center frequency");
    model.param().set("c0", "343[m/s]", "Speed of sound");
    model.param().set("rho0", "1.2[kg/m^3]", "Density");
    model.param().set("lam0", "c0/f0", "Wavelength at f0");
    model.param().set("Vol", "412.5[m^3]", "Room volume");
    model.param().set("s_default", "0.05", "Scattering coefficient of flat surfaces");
    model.param().set("s_diffuser", "0.5", "Scattering coefficient of diffusers");
    model.param().set("s_seats", "0.6", "Scattering coefficient of seating area");

//    In the Home toolbar, click Parameters and choose Add > Parameters.

    model.param().create("par2");

//    In the Settings window for Parameters, type Parameters 2 - Source and Receiver Positions in the Label text field.

    model.param("par2").label("Parameters 2 - Source and Receiver Positions");

//    Locate the Parameters section.
//    Click Load from File.
//    Browse to the model's Application Library folder and double-click the file small_concert_hall_parameters_source_positions.txt.
//    To import content from file, use:
//    model.param("par2").loadFile("FILENAME");
    model.param("par2").set("x_src", "1[m]", "Omnidirectional source x-coordinate");
    model.param("par2").set("y_src", "-1[m]", "Omnidirectional source y-coordinate");
    model.param("par2").set("z_src", "1.5[m]", "Omnidirectional source z-coordinate");
    model.param("par2").set("x_rec", "7[m]", "Receiver x-coordinate");
    model.param("par2").set("y_rec", "1[m]", "Receiver y-coordinate");
    model.param("par2").set("z_rec", "1.5[m]", "Receiver z-coordinate");
    model.param("par2")
         .set("dsr", "sqrt((x_src-x_rec)^2+(y_src-y_rec)^2+(z_src-z_rec)^2)", "Source to receiver distance");
    model.param("par2").set("x_spk", "0.8[m]", "Loudspeaker x-coordinate");
    model.param("par2").set("y_spk", "2[m]", "Loudspeaker y-coordinate");
    model.param("par2").set("z_spk", "2.5[m]", "Loudspeaker z-coordinate");
    model.param("par2").set("alpha0", "90[deg]", "Loudspeaker orientation (Euler angle)");
    model.param("par2").set("beta0", "15[deg]", "Loudspeaker orientation (Euler angle)");
    model.param("par2").set("gamma0", "-100[deg]", "Loudspeaker orientation (Euler angle)");

//    In the Home toolbar, click Parameters and choose Add > Parameters.

    model.param().create("par3");

//    In the Settings window for Parameters, type Parameters 3 - Source and Receiver Settings in the Label text field.

    model.param("par3").label("Parameters 3 - Source and Receiver Settings");

//    Locate the Parameters section.
//    Click Load from File.
//    Browse to the model's Application Library folder and double-click the file small_concert_hall_parameters_source_settings.txt.
//    To import content from file, use:
//    model.param("par3").loadFile("FILENAME");
    model.param("par3").set("L0_src", "100[dB]", "Omnidirectional source sound pressure level at R0_src");
    model.param("par3").set("R0_src", "1[m]", "Reference distance");
    model.param("par3").set("L0_spk", "0[dB]", "Loudspeaker gain");
    model.param("par3").set("R0_spk", "1[m]", "Reference distance");
    model.param("par3").set("r_rec", "0.3[m]", "Receiver radius");
    model.param("par3").set("dt", "0.01[s]", "Time interval");
    model.param("par3")
         .set("Nrays_min", "(4.34/r_rec)^2*Vol/pi/c0/dt", "Recommended minimum number of released rays");
    model.param("par3").set("Nrays", "1000*ceil(Nrays_min/1000)", "Number of released rays");

//    Create an interpolation function to import the loudspeaker directivity data.
//    In the Home toolbar, click Functions and choose Global > Interpolation.

    model.func().create("int1", "Interpolation");

//    In the Settings window for Interpolation, locate the Definition section.
//    From the Data source list, select File.

    model.func("int1").set("source", "file");

//    Click Browse.
//    Browse to the model's Application Library folder and double-click the file small_concert_hall_radiation_balloon.txt.

    model.func("int1").set("filename", "small_concert_hall_radiation_balloon.txt");

//    Click Import.

    model.func("int1").importData();

//    Locate the Data Column Settings section.
//    In the table, click to select the cell at row number 1 and column number 1.
//    In the Unit text field, type deg.

    model.func("int1").setIndex("argunit", "deg", 0);

//    In the table, click to select the cell at row number 2 and column number 1.
//    In the Unit text field, type deg.

    model.func("int1").setIndex("argunit", "deg", 1);

//    In the table, click to select the cell at row number 3 and column number 1.
//    In the Unit text field, type Hz.

    model.func("int1").setIndex("argunit", "Hz", 2);

//    In the table, click to select the cell at row number 4 and column number 1.
//    In the Name text field, type preal.

    model.func("int1").setEntry("funcnames", "col4", "preal");

//    In the Unit text field, type Pa.

    model.func("int1").setIndex("fununit", "Pa", 0);

//    In the table, enter the following settings:

    model.func("int1").setEntry("columnType", "col5", "value");

//    In the Name text field, type pimag.

    model.func("int1").setEntry("funcnames", "col5", "pimag");

//    In the Unit text field, type Pa.

    model.func("int1").setIndex("fununit", "Pa", 1);

//    Proceed and set up interpolation functions for the absorption coefficients of the different surfaces in the concert hall. The data is easily stored in one <c>.txt</c> file. Also define an interpolation function for the amplitude attenuation of air (given at 50% relative humidity and 20°C).
//    In the Home toolbar, click Functions and choose Global > Interpolation.

    model.func().create("int2", "Interpolation");

//    In the Settings window for Interpolation, locate the Definition section.
//    From the Data source list, select File.

    model.func("int2").set("source", "file");

//    Click Browse.
//    Browse to the model's Application Library folder and double-click the file small_concert_hall_absorption_parameters.txt.

    model.func("int2").set("filename", "small_concert_hall_absorption_parameters.txt");

//    Click Import.

    model.func("int2").importData();

//    Locate the Data Column Settings section.
//    In the table, enter the following settings:

    model.func("int2").setEntry("columnType", "col2", "value");
    model.func("int2").setEntry("columnType", "col3", "value");
    model.func("int2").setEntry("columnType", "col5", "value");
    model.func("int2").setEntry("columnType", "col6", "value");
    model.func("int2").setEntry("columnType", "col7", "value");
    model.func("int2").setEntry("columnType", "col8", "value");

//    In the table, click to select the cell at row number 1 and column number 1.
//    In the Unit text field, type Hz.

    model.func("int2").setIndex("argunit", "Hz", 0);

//    In the table, click to select the cell at row number 2 and column number 1.
//    In the Name text field, type a_walls.

    model.func("int2").setEntry("funcnames", "col2", "a_walls");

//    In the Unit text field, type 1.

    model.func("int2").setIndex("fununit", "1", 0);

//    In the table, click to select the cell at row number 3 and column number 1.
//    In the Name text field, type a_entrance.

    model.func("int2").setEntry("funcnames", "col3", "a_entrance");

//    In the Unit text field, type 1.

    model.func("int2").setIndex("fununit", "1", 1);

//    In the table, click to select the cell at row number 4 and column number 1.
//    In the Name text field, type a_windows.

    model.func("int2").setEntry("funcnames", "col4", "a_windows");

//    In the Unit text field, type 1.

    model.func("int2").setIndex("fununit", "1", 2);

//    In the table, click to select the cell at row number 5 and column number 1.
//    In the Name text field, type a_floor.

    model.func("int2").setEntry("funcnames", "col5", "a_floor");

//    In the Unit text field, type 1.

    model.func("int2").setIndex("fununit", "1", 3);

//    In the table, click to select the cell at row number 6 and column number 1.
//    In the Name text field, type a_diffuser.

    model.func("int2").setEntry("funcnames", "col6", "a_diffuser");

//    In the Unit text field, type 1.

    model.func("int2").setIndex("fununit", "1", 4);

//    In the table, click to select the cell at row number 7 and column number 1.
//    In the Name text field, type a_seats.

    model.func("int2").setEntry("funcnames", "col7", "a_seats");

//    In the Unit text field, type 1.

    model.func("int2").setIndex("fununit", "1", 5);

//    In the table, click to select the cell at row number 8 and column number 1.
//    In the Name text field, type a_absorbers.

    model.func("int2").setEntry("funcnames", "col8", "a_absorbers");

//    In the Unit text field, type 1.

    model.func("int2").setIndex("fununit", "1", 6);

//    In the Home toolbar, click Functions and choose Global > Interpolation.

    model.func().create("int3", "Interpolation");

//    In the Settings window for Interpolation, locate the Definition section.
//    From the Data source list, select File.

    model.func("int3").set("source", "file");

//    Click Browse.
//    Browse to the model's Application Library folder and double-click the file small_concert_hall_air_attenuation.txt.

    model.func("int3").set("filename", "small_concert_hall_air_attenuation.txt");

//    Click Import.

    model.func("int3").importData();

//    In the Function name text field, type a_air.

    model.func("int3").set("funcname", "a_air");

//    Locate the Interpolation and Extrapolation section.
//    From the Interpolation list, select Nearest neighbor.

    model.func("int3").set("interp", "neighbor");

//    Locate the Units section.
//    In the Argument table, enter the following settings:

    model.func("int3").setIndex("argunit", "Hz", 0);
    model.func("int3").setIndex("fununit", "1/m", 0);

//    In the Function table, enter the following settings:
//    Now create the rotated coordinate system that will represent the orientation of the directional loudspeaker. When working on your own model, it is recommended to run a quick study to visualize the coordinate system and ensure that the correct angles are entered.
//    In the Definitions toolbar, click Coordinate Systems and choose Rotated System.

    model.component("comp1").coordSystem().create("sys2", "Rotated");

//    In the Settings window for Rotated System, locate the Rotation section.
//    Find the Euler angles subsection.
//    In the α text field, type alpha0.

    model.component("comp1").coordSystem("sys2").set("angle", new String[]{"alpha0", "0", "0"});

//    In the β text field, type beta0.

    model.component("comp1").coordSystem("sys2").set("angle", new String[]{"alpha0", "beta0", "0"});

//    In the γ text field, type gamma0.

    model.component("comp1").coordSystem("sys2").setIndex("angle", "gamma0", 2);

//    Add a point to the geometry to represent the loudspeaker position. This will allow to later plot the rotated coordinate system. Also add a sphere corresponding to the receiver. The default recommendation is to use a receiver radius of 0.3 m, which corresponds to the standard width of a seat. For different applications, especially smaller spaces like a car cabin, it is recommended to decrease the value of the receiver radius.
//    In the Geometry toolbar, click More Primitives and choose Point.

    model.component("comp1").geom("geom1").run("sel7");
    model.component("comp1").geom("geom1").create("pt1", "Point");

//    In the Settings window for Point, locate the Point section.
//    In the x text field, type x_spk.

    model.component("comp1").geom("geom1").feature("pt1").setIndex("p", "x_spk", 0);

//    In the y text field, type y_spk.

    model.component("comp1").geom("geom1").feature("pt1").setIndex("p", "y_spk", 1);

//    In the z text field, type z_spk.

    model.component("comp1").geom("geom1").feature("pt1").setIndex("p", "z_spk", 2);

//    In the Geometry toolbar, click Sphere.

    model.component("comp1").geom("geom1").run("pt1");
    model.component("comp1").geom("geom1").create("sph1", "Sphere");

//    In the Settings window for Sphere, locate the Object Type section.
//    From the Type list, select Surface.

    model.component("comp1").geom("geom1").feature("sph1").set("type", "surface");

//    Locate the Size section.
//    In the Radius text field, type r_rec.

    model.component("comp1").geom("geom1").feature("sph1").set("r", "r_rec");

//    Locate the Position section.
//    In the x text field, type x_rec.

    model.component("comp1").geom("geom1").feature("sph1").set("pos", new String[]{"x_rec", "0", "0"});

//    In the y text field, type y_rec.

    model.component("comp1").geom("geom1").feature("sph1").set("pos", new String[]{"x_rec", "y_rec", "0"});

//    In the z text field, type z_rec.

    model.component("comp1").geom("geom1").feature("sph1").set("pos", new String[]{"x_rec", "y_rec", "z_rec"});

//    Locate the Selections of Resulting Entities section.
//    Select the Resulting objects selection checkbox.

    model.component("comp1").geom("geom1").feature("sph1").set("selresult", true);

//    From the Show in physics list, select Boundary selection.

    model.component("comp1").geom("geom1").feature("sph1").set("selresultshow", "bnd");

//    In the Geometry toolbar, click Build All.

    model.component("comp1").geom("geom1").run("fin");

//    Import the variables that define the room acoustic quality metric estimates. They include the reverberation time (<c>T60</c>), based on the Sabine and Eyring estimation equations, clarity (<c>C80</c>), definition (<c>D</c>), and center time (<c>ts</c>). This also requires setting up integration operators for all the surfaces.
//    In the Model Builder window, expand the Component 1 (comp1) > Definitions node.
//    Right-click Definitions and choose Nonlocal Couplings > Integration.

    model.component("comp1").cpl().create("intop1", "Integration");
    model.component("comp1").cpl("intop1").set("axisym", true);

//    In the Settings window for Integration, type intop_windows in the Operator name text field.

    model.component("comp1").cpl("intop1").set("opname", "intop_windows");

//    Locate the Source Selection section.
//    From the Geometric entity level list, select Boundary.

    model.component("comp1").cpl("intop1").selection().geom("geom1", 2);

//    From the Selection list, select Windows.

    model.component("comp1").cpl("intop1").selection().named("geom1_sel1");

//    In the Definitions toolbar, click Nonlocal Couplings and choose Integration.

    model.component("comp1").cpl().create("intop2", "Integration");
    model.component("comp1").cpl("intop2").set("axisym", true);

//    In the Settings window for Integration, type intop_seats in the Operator name text field.

    model.component("comp1").cpl("intop2").set("opname", "intop_seats");

//    Locate the Source Selection section.
//    From the Geometric entity level list, select Boundary.

    model.component("comp1").cpl("intop2").selection().geom("geom1", 2);

//    From the Selection list, select Seats.

    model.component("comp1").cpl("intop2").selection().named("geom1_sel2");

//    In the Definitions toolbar, click Nonlocal Couplings and choose Integration.

    model.component("comp1").cpl().create("intop3", "Integration");
    model.component("comp1").cpl("intop3").set("axisym", true);

//    In the Settings window for Integration, type intop_diffusers in the Operator name text field.

    model.component("comp1").cpl("intop3").set("opname", "intop_diffusers");

//    Locate the Source Selection section.
//    From the Geometric entity level list, select Boundary.

    model.component("comp1").cpl("intop3").selection().geom("geom1", 2);

//    From the Selection list, select Diffusers.

    model.component("comp1").cpl("intop3").selection().named("geom1_sel3");

//    In the Definitions toolbar, click Nonlocal Couplings and choose Integration.

    model.component("comp1").cpl().create("intop4", "Integration");
    model.component("comp1").cpl("intop4").set("axisym", true);

//    In the Settings window for Integration, type intop_floor in the Operator name text field.

    model.component("comp1").cpl("intop4").set("opname", "intop_floor");

//    Locate the Source Selection section.
//    From the Geometric entity level list, select Boundary.

    model.component("comp1").cpl("intop4").selection().geom("geom1", 2);

//    From the Selection list, select Floor.

    model.component("comp1").cpl("intop4").selection().named("geom1_sel4");

//    In the Definitions toolbar, click Nonlocal Couplings and choose Integration.

    model.component("comp1").cpl().create("intop5", "Integration");
    model.component("comp1").cpl("intop5").set("axisym", true);

//    In the Settings window for Integration, type intop_entrance in the Operator name text field.

    model.component("comp1").cpl("intop5").set("opname", "intop_entrance");

//    Locate the Source Selection section.
//    From the Geometric entity level list, select Boundary.

    model.component("comp1").cpl("intop5").selection().geom("geom1", 2);

//    From the Selection list, select Entrance.

    model.component("comp1").cpl("intop5").selection().named("geom1_sel5");

//    In the Definitions toolbar, click Nonlocal Couplings and choose Integration.

    model.component("comp1").cpl().create("intop6", "Integration");
    model.component("comp1").cpl("intop6").set("axisym", true);

//    In the Settings window for Integration, type intop_walls in the Operator name text field.

    model.component("comp1").cpl("intop6").set("opname", "intop_walls");

//    Locate the Source Selection section.
//    From the Geometric entity level list, select Boundary.

    model.component("comp1").cpl("intop6").selection().geom("geom1", 2);

//    From the Selection list, select Walls.

    model.component("comp1").cpl("intop6").selection().named("geom1_sel6");

//    In the Definitions toolbar, click Nonlocal Couplings and choose Integration.

    model.component("comp1").cpl().create("intop7", "Integration");
    model.component("comp1").cpl("intop7").set("axisym", true);

//    In the Settings window for Integration, type intop_absorbers in the Operator name text field.

    model.component("comp1").cpl("intop7").set("opname", "intop_absorbers");

//    Locate the Source Selection section.
//    From the Geometric entity level list, select Boundary.

    model.component("comp1").cpl("intop7").selection().geom("geom1", 2);

//    From the Selection list, select Absorbers.

    model.component("comp1").cpl("intop7").selection().named("geom1_sel7");

//    Right-click Definitions and choose Variables.

    model.component("comp1").variable().create("var1");

//    In the Settings window for Variables, type Variables: Quality Metric Estimates in the Label text field.

    model.component("comp1").variable("var1").label("Variables: Quality Metric Estimates");

//    Locate the Variables section.
//    Click Load from File.
//    Browse to the model's Application Library folder and double-click the file small_concert_hall_variables.txt.
//    To import content from file, use:
//    model.component("comp1").variable("var1").loadFile("FILENAME");
    model.component("comp1").variable("var1")
         .set("A", "intop_windows(1)*a_windows(f0)+intop_seats(1)*a_seats(f0)+intop_diffusers(1)*a_diffuser(f0)+intop_floor(1)*a_floor(f0)+intop_entrance(1)*a_entrance(f0)+intop_walls(1)*a_walls(f0)+intop_absorbers(1)*a_absorbers(f0)", "Total absorption");
    model.component("comp1").variable("var1")
         .set("S", "intop_windows(1)+intop_seats(1)+intop_diffusers(1)+intop_floor(1)+intop_entrance(1)+intop_walls(1)+intop_absorbers(1)", "Total surface area");
    model.component("comp1").variable("var1")
         .set("T60_S", "0.161[s/m]*Vol/(A+8*a_air(f0)*Vol)", "Reverberation time (Sabine)");
    model.component("comp1").variable("var1")
         .set("T60_Sna", "0.161[s/m]*Vol/A", "Reverberation time (Sabine, no air absorption)");
    model.component("comp1").variable("var1")
         .set("T60_E", "0.161[s/m]*Vol/(-S*log(1-A/S)+8*a_air(f0)*Vol)", "Reverberation time (Eyring)");
    model.component("comp1").variable("var1").set("T0", "T60_S", "Reverberation time");
    model.component("comp1").variable("var1").set("Ed", "1/(4*pi*c0*dsr^2)", "Direct energy");
    model.component("comp1").variable("var1")
         .set("Ee50", "T0/(13.8*Vol)*(exp(-A/S)-exp(-(13.8/T0*50[ms]+A/S)))", "Early energy 50 ms");
    model.component("comp1").variable("var1")
         .set("El50", "T0/(13.8*Vol)*(exp(-(13.8/T0*50[ms]+A/S)))", "Late energy 50 ms");
    model.component("comp1").variable("var1")
         .set("Ee80", "T0/(13.8*Vol)*(exp(-A/S)-exp(-(13.8/T0*80[ms]+A/S)))", "Early energy 80 ms");
    model.component("comp1").variable("var1")
         .set("El80", "T0/(13.8*Vol)*(exp(-(13.8/T0*80[ms]+A/S)))", "Late energy 80 ms");
    model.component("comp1").variable("var1").set("C50", "10*log10((Ed+Ee50)/El50)", "Clarity 50 estimate");
    model.component("comp1").variable("var1").set("C80", "10*log10((Ed+Ee80)/El80)", "Clarity 80 estimate");
    model.component("comp1").variable("var1").set("D", "10^(C50/10)/(1+10^(C50/10))*100", "Definition estimate");
    model.component("comp1").variable("var1").set("ts", "T0/13.8*(A/S+1)", "Center time estimate");

//    Proceed to set up and define the physics and boundary conditions of the model. To compute the impulse response, it is necessary to model the power along the rays and count the reflections. In the model the intensity is also computed along the rays. The intensity represents spatially local properties of the acoustic field approximated by the rays. The model only uses a surface mesh. Propagation in the unmeshed domains requires the input of material properties at the interface level (in the section <l>Material Properties of Exterior and Unmeshed Domains</l>). Set up boundary conditions for the different walls. All the boundary conditions are defined as <l>Mixed diffuse and specular reflection</l>, with either a default or specific scattering coefficient.
//    In the Model Builder window, under Component 1 (comp1), click Ray Acoustics (rac).
//    In the Settings window for Ray Acoustics, locate the Intensity Computation section.
//    From the Intensity computation list, select Compute intensity and power.

    model.component("comp1").physics("rac").prop("IntensityComputation")
         .setIndex("IntensityComputation", "ComputeIntensityAndPower", 0);

//    Locate the Material Properties of Exterior and Unmeshed Domains section.
//    In the \[c_{\textrm{ext}}\] text field, type c0.

    model.component("comp1").physics("rac").prop("cext").setIndex("cext", "c0", 0);

//    In the \[\rho_{\textrm{ext}}\] text field, type rho0.

    model.component("comp1").physics("rac").prop("rhoext").setIndex("rhoext", "rho0", 0);

//    In the \[\alpha_{\textrm{ext}}\] text field, type a_air(f0).

    model.component("comp1").physics("rac").prop("alphaext").setIndex("alphaext", "a_air(f0)", 0);

//    In the Model Builder window, under Component 1 (comp1) > Ray Acoustics (rac), click Ray Properties 1.
//    In the Settings window for Ray Properties, locate the Ray Properties section.
//    In the \[f\] text field, type f0.

    model.component("comp1").physics("rac").feature("op1").set("f", "f0");

//    In the Physics toolbar, click Boundaries and choose Wall.

    model.component("comp1").physics("rac").create("wall2", "RayAcousticsWall", 2);

//    In the Settings window for Wall, type Wall: Walls in the Label text field.

    model.component("comp1").physics("rac").feature("wall2").label("Wall: Walls");

//    Locate the Boundary Selection section.
//    From the Selection list, select Walls.

    model.component("comp1").physics("rac").feature("wall2").selection().named("geom1_sel6");

//    Locate the Wall Condition section.
//    In the \[s\] text field, type s_default.

    model.component("comp1").physics("rac").feature("wall2").set("s", "s_default");

//    In the \[\alpha\] text field, type a_walls(f0).

    model.component("comp1").physics("rac").feature("wall2").set("alpha", "a_walls(f0)");

//    In the Physics toolbar, click Boundaries and choose Wall.

    model.component("comp1").physics("rac").create("wall3", "RayAcousticsWall", 2);

//    In the Settings window for Wall, type Wall: Entrance in the Label text field.

    model.component("comp1").physics("rac").feature("wall3").label("Wall: Entrance");

//    Locate the Boundary Selection section.
//    From the Selection list, select Entrance.

    model.component("comp1").physics("rac").feature("wall3").selection().named("geom1_sel5");

//    Locate the Wall Condition section.
//    In the \[s\] text field, type s_default.

    model.component("comp1").physics("rac").feature("wall3").set("s", "s_default");

//    In the \[\alpha\] text field, type a_entrance(f0).

    model.component("comp1").physics("rac").feature("wall3").set("alpha", "a_entrance(f0)");

//    In the Physics toolbar, click Boundaries and choose Wall.

    model.component("comp1").physics("rac").create("wall4", "RayAcousticsWall", 2);

//    In the Settings window for Wall, type Wall: Windows in the Label text field.

    model.component("comp1").physics("rac").feature("wall4").label("Wall: Windows");

//    Locate the Boundary Selection section.
//    From the Selection list, select Windows.

    model.component("comp1").physics("rac").feature("wall4").selection().named("geom1_sel1");

//    Locate the Wall Condition section.
//    In the \[s\] text field, type s_default.

    model.component("comp1").physics("rac").feature("wall4").set("s", "s_default");

//    In the \[\alpha\] text field, type a_windows(f0).

    model.component("comp1").physics("rac").feature("wall4").set("alpha", "a_windows(f0)");

//    In the Physics toolbar, click Boundaries and choose Wall.

    model.component("comp1").physics("rac").create("wall5", "RayAcousticsWall", 2);

//    In the Settings window for Wall, type Wall: Floor in the Label text field.

    model.component("comp1").physics("rac").feature("wall5").label("Wall: Floor");

//    Locate the Boundary Selection section.
//    From the Selection list, select Floor.

    model.component("comp1").physics("rac").feature("wall5").selection().named("geom1_sel4");

//    Locate the Wall Condition section.
//    In the \[s\] text field, type s_default.

    model.component("comp1").physics("rac").feature("wall5").set("s", "s_default");

//    In the \[\alpha\] text field, type a_floor(f0).

    model.component("comp1").physics("rac").feature("wall5").set("alpha", "a_floor(f0)");

//    In the Physics toolbar, click Boundaries and choose Wall.

    model.component("comp1").physics("rac").create("wall6", "RayAcousticsWall", 2);

//    In the Settings window for Wall, type Wall: Diffusers in the Label text field.

    model.component("comp1").physics("rac").feature("wall6").label("Wall: Diffusers");

//    Locate the Boundary Selection section.
//    From the Selection list, select Diffusers.

    model.component("comp1").physics("rac").feature("wall6").selection().named("geom1_sel3");

//    Locate the Wall Condition section.
//    In the \[s\] text field, type s_diffuser.

    model.component("comp1").physics("rac").feature("wall6").set("s", "s_diffuser");

//    In the \[\alpha\] text field, type a_diffuser(f0).

    model.component("comp1").physics("rac").feature("wall6").set("alpha", "a_diffuser(f0)");

//    In this model the scattering coefficient <c>s_diffuser</c> is constant across the frequency bands. It can of course also be defined as an interpolation function that depends on <c>f0</c>.
//    In the Physics toolbar, click Boundaries and choose Wall.

    model.component("comp1").physics("rac").create("wall7", "RayAcousticsWall", 2);

//    In the Settings window for Wall, type Wall: Absorbers in the Label text field.

    model.component("comp1").physics("rac").feature("wall7").label("Wall: Absorbers");

//    Locate the Boundary Selection section.
//    From the Selection list, select Absorbers.

    model.component("comp1").physics("rac").feature("wall7").selection().named("geom1_sel7");

//    Locate the Wall Condition section.
//    In the \[s\] text field, type s_default.

    model.component("comp1").physics("rac").feature("wall7").set("s", "s_default");

//    In the \[\alpha\] text field, type a_absorbers(f0).

    model.component("comp1").physics("rac").feature("wall7").set("alpha", "a_absorbers(f0)");

//    In the Physics toolbar, click Boundaries and choose Wall.

    model.component("comp1").physics("rac").create("wall8", "RayAcousticsWall", 2);

//    In the Settings window for Wall, type Wall: Seats (Top) in the Label text field.

    model.component("comp1").physics("rac").feature("wall8").label("Wall: Seats (Top)");

//    Locate the Boundary Selection section.
//    From the Selection list, select Manual.
//    Select Boundary 41.

    model.component("comp1").physics("rac").feature("wall8").selection().set(41);

//    Locate the Wall Condition section.
//    In the \[s\] text field, type s_seats.

    model.component("comp1").physics("rac").feature("wall8").set("s", "s_seats");

//    In the \[\alpha\] text field, type a_seats(f0).

    model.component("comp1").physics("rac").feature("wall8").set("alpha", "a_seats(f0)");

//    In the Physics toolbar, click Attributes and choose Sound Pressure Level Calculation.

    model.component("comp1").physics("rac").feature("wall8").create("spl1", "SoundPressureLevelBoundary", 2);

//    In the Settings window for Sound Pressure Level Calculation, locate the Smoothing section.

    return model;
  }

  public static Model run2(Model model) {
//    Select the Compute smoothed accumulated variable checkbox.

    model.component("comp1").physics("rac").feature("wall8").feature("spl1")
         .set("ComputeSmoothedAccumulatedVariable", true);

//    In the Physics toolbar, click Boundaries and choose Wall.

    model.component("comp1").physics("rac").create("wall9", "RayAcousticsWall", 2);

//    In the Settings window for Wall, type Wall: Seats (Around) in the Label text field.

    model.component("comp1").physics("rac").feature("wall9").label("Wall: Seats (Around)");

//    Locate the Boundary Selection section.
//    From the Selection list, select Manual.
//    Select Boundaries 39, 40, 42, 67.

    model.component("comp1").physics("rac").feature("wall9").selection().set(39, 40, 42, 67);

//    Locate the Wall Condition section.
//    In the \[s\] text field, type s_seats.

    model.component("comp1").physics("rac").feature("wall9").set("s", "s_seats");

//    In the \[\alpha\] text field, type a_seats(f0).

    model.component("comp1").physics("rac").feature("wall9").set("alpha", "a_seats(f0)");

//    The source is defined here with its spatial directivity, reference level, and reference distance. For spatial directivity, the default value shows the angle variables in the cosine and sine expressions needed to define the directivity. In this case, it is set to 0[dB] to obtain an omnidirectional point source.
//    In the Physics toolbar, click Global and choose Source with Directivity.

    model.component("comp1").physics("rac").create("swd1", "SourceWithDirectivity", -1);

//    In the Settings window for Source with Directivity, locate the Initial Position section.
//    Specify the \[\mathbf{q}_0\] vector as

    model.component("comp1").physics("rac").feature("swd1").set("q0", new String[]{"x_src", "y_src", "z_src"});

//    Locate the Ray Direction Vector section.
//    In the \[N_\textrm{w}\] text field, type Nrays.

    model.component("comp1").physics("rac").feature("swd1").setIndex("Nw", "Nrays", 0);

//    Locate the Intensity and Power section.
//    In the \[D(\varphi,\theta)\] text field, type 0[dB].

    model.component("comp1").physics("rac").feature("swd1").set("D", "0[dB]");

//    In the \[L_\textrm{ref}\] text field, type L0_src.

    model.component("comp1").physics("rac").feature("swd1").set("Lref", "L0_src");

//    In the \[R_\textrm{ref}\] text field, type R0_src.

    model.component("comp1").physics("rac").feature("swd1").set("Rref", "R0_src");

//    A second source is included in the model to demonstrate the case of a directional loudspeaker source. In this case, the radiation data is given as the sound pressure measured one meter away from the source; it therefore needs to be converted to sound pressure level.
//    In the Physics toolbar, click Global and choose Source with Directivity.

    model.component("comp1").physics("rac").create("swd2", "SourceWithDirectivity", -1);

//    In the Settings window for Source with Directivity, locate the Coordinate System Selection section.
//    From the Coordinate system list, select Rotated System 2 (sys2).

    model.component("comp1").physics("rac").feature("swd2").set("coordinateSystem", "sys2");

//    Locate the Initial Position section.
//    Specify the \[\mathbf{q}_0\] vector as

    model.component("comp1").physics("rac").feature("swd2").set("q0", new String[]{"x_spk", "y_spk", "z_spk"});

//    Locate the Ray Direction Vector section.
//    In the \[N_\textrm{w}\] text field, type Nrays.

    model.component("comp1").physics("rac").feature("swd2").setIndex("Nw", "Nrays", 0);

//    Locate the Intensity and Power section.
//    In the \[D(\varphi,\theta)\] text field, type 20*log10(abs(preal(rac.swd2.phi,rac.swd2.theta,f0)+i*pimag(rac.swd2.phi,rac.swd2.theta,f0))/sqrt(2)/20e-6[Pa]).

    model.component("comp1").physics("rac").feature("swd2")
         .set("D", "20*log10(abs(preal(rac.swd2.phi,rac.swd2.theta,f0)+i*pimag(rac.swd2.phi,rac.swd2.theta,f0))/sqrt(2)/20e-6[Pa])");

//    In the \[L_\textrm{ref}\] text field, type L0_spk.

    model.component("comp1").physics("rac").feature("swd2").set("Lref", "L0_spk");

//    In the \[R_\textrm{ref}\] text field, type R0_spk.

    model.component("comp1").physics("rac").feature("swd2").set("Rref", "R0_spk");

//    In the Physics toolbar, click Global and choose Ray Termination.

    model.component("comp1").physics("rac").create("rt1", "RayTermination", -1);

//    Add a termination condition to end the propagation of rays once their energy drops below a certain threshold. This makes computations faster by removing rays which do not have a significant contribution anymore. The <em>if</em> statement and <em>isdefined</em> operator allow to select the correct variable according to the active source.
//    In the Settings window for Ray Termination, locate the Termination Criteria section.
//    From the Spatial extents of ray propagation list, select Bounding box, from geometry.

    model.component("comp1").physics("rac").feature("rt1")
         .set("SpatialExtentsOfRayPropagation", "BoundingBoxFromGeometry");

//    From the Additional termination criteria list, select Power.

    model.component("comp1").physics("rac").feature("rt1").set("AdditionalTerminationCriteria", "Power");

//    In the \[Q_{\textrm{th}}\] text field, type if(isdefined(rac.swd1.Q0),rac.swd1.Q0*1e-7,rac.swd2.Q0*1e-7).

    model.component("comp1").physics("rac").feature("rt1")
         .set("Qth", "if(isdefined(rac.swd1.Q0),rac.swd1.Q0*1e-7,rac.swd2.Q0*1e-7)");

//    The <l>Receiver</l> feature allows to gather the data needed for <l>Impulse Response</l> plots while solving the model, making postprocessing nearly instantaneous without affecting solution time.
//    In the Physics toolbar, click Boundaries and choose Receiver.

    model.component("comp1").physics("rac").create("rec1", "Receiver", 2);

//    In the Settings window for Receiver, locate the Boundary Selection section.
//    From the Selection list, select Sphere 1.

    model.component("comp1").physics("rac").feature("rec1").selection().named("geom1_sph1_bnd");

//    Now create the mesh. In ray tracing simulations for room acoustics, the mesh is used to detect the collisions between rays and boundaries. Therefore, only the boundaries need to be meshed and the element size can be set to a coarse value without compromising accuracy.
//    In the Model Builder window, under Component 1 (comp1), click Mesh 1.
//    In the Settings window for Mesh, locate the Physics-Controlled Mesh section.
//    From the Element size list, select Extra coarse.

    model.component("comp1").mesh("mesh1").autoMeshSize(8);

//    Locate the Sequence Type section.
//    From the list, select User-controlled mesh.

    model.component("comp1").mesh("mesh1").automatic(false);

//    Add a finer mesh on the surface where the SPL is computed and on the receiver sphere.
//    In the Model Builder window, under Component 1 (comp1) > Mesh 1, click Size 2.
//    In the Settings window for Size, locate the Element Size Parameters section.
//    In the Maximum element size text field, type r_rec/3.

    model.component("comp1").mesh("mesh1").feature("size2").set("hmax", "r_rec/3");

//    Clear the Minimum element size checkbox.

    model.component("comp1").mesh("mesh1").feature("size2").set("hminactive", false);

//    In the Model Builder window, click Free Triangular 1.
//    In the Settings window for Free Triangular, locate the Boundary Selection section.
//    From the Selection list, select All boundaries.

    model.component("comp1").mesh("mesh1").feature("ftri1").selection().all();

//    Right-click Free Triangular 1 and choose Size.

    model.component("comp1").mesh("mesh1").feature("ftri1").create("size1", "Size");

//    In the Settings window for Size, locate the Geometric Entity Selection section.
//    Click Clear Selection.

    model.component("comp1").mesh("mesh1").feature("ftri1").feature("size1").selection().set();

//    Select Boundary 41.

    model.component("comp1").mesh("mesh1").feature("ftri1").feature("size1").selection().set(41);

//    Locate the Element Size section.
//    Click the Custom button.

    model.component("comp1").mesh("mesh1").feature("ftri1").feature("size1").set("custom", true);

//    Locate the Element Size Parameters section.
//    Select the Maximum element size checkbox.

    model.component("comp1").mesh("mesh1").feature("ftri1").feature("size1").set("hmaxactive", true);

//    In the associated text field, type 0.3.

    model.component("comp1").mesh("mesh1").feature("ftri1").feature("size1").set("hmax", 0.3);

//    Mesh the vertices that are not part of the model boundaries, in this case the geometry point representing the directional loudspeaker..
//    In the Mesh toolbar, click More Generators and choose Vertex.

    model.component("comp1").mesh("mesh1").create("vtx1", "Vertex");

//    In the Settings window for Vertex, locate the Point Selection section.
//    Click Paste Selection.
//    In the Paste Selection dialog, type 11 in the Selection text field.
//    Click OK.

    model.component("comp1").mesh("mesh1").feature("vtx1").selection().set(11);

//    In the Settings window for Vertex, click Build All.

    model.component("comp1").mesh("mesh1").run();

//    Proceed and solve the model with the omnidirectional source by adding a parametric sweep over the center frequency variable <c>f0</c>. This represents the center frequency of the octave bands analyzed in this model, in order to get a broadband response. The first time you set up and solve the model it can be useful to reduce the number of rays by changing the value of the parameter <c>Nrays</c> to, for example, 1000. This will make solving and postprocessing faster. Remember that the quality of the results in acoustic ray tracing increase for an increasing number of rays and more narrow frequency bands (given boundary condition data with the adequate resolution). In the <em>Ray Acoustics</em> interface the impulse response plot can handle octave, 1/3-octave, and 1/6-octave data.
//    In the Model Builder window, click Study 1.
//    In the Settings window for Study, type Study 1 - Omnidirectional Source in the Label text field.

    model.study("std1").label("Study 1 - Omnidirectional Source");

//    In the Model Builder window, under Study 1 - Omnidirectional Source, click Step 1: Ray Tracing.
//    In the Settings window for Ray Tracing, locate the Study Settings section.
//    From the Time unit list, select s.

    model.study("std1").feature("rtrac").set("tunit", "s");

//    In the Output times text field, type 0 1.6.

    model.study("std1").feature("rtrac").set("tlist", "0 1.6");

//    For optimal performance only enter 0 and the end time for the simulation. In postprocessing, when reconstructing the impulse response, additional exact time steps for all the wall reflections are used and rendered.
//    Locate the Physics and Variables Selection section.
//    Select the Modify model configuration for study step checkbox.

    model.study("std1").feature("rtrac").set("useadvanceddisable", true);

//    In the tree, select Component 1 (comp1) > Ray Acoustics (rac) > Source with Directivity 2.
//    Click Disable.

    model.study("std1").feature("rtrac").set("disabledphysics", new String[]{"rac/swd2"});

//    In the Study toolbar, click Parametric Sweep.

    model.study("std1").create("param", "Parametric");

//    Using the parametric sweep is important as this gives the frequency resolution (here in full octaves). The ray propagation model is solved once per frequency band.
//    In the Settings window for Parametric Sweep, locate the Study Settings section.
//    Click Add.

    model.study("std1").feature("param").setIndex("pname", "alpha0", 0);
    model.study("std1").feature("param").setIndex("plistarr", "", 0);
    model.study("std1").feature("param").setIndex("punit", "rad", 0);
    model.study("std1").feature("param").setIndex("pname", "alpha0", 0);
    model.study("std1").feature("param").setIndex("plistarr", "", 0);
    model.study("std1").feature("param").setIndex("punit", "rad", 0);

//    In the table, enter the following settings:

    model.study("std1").feature("param").setIndex("pname", "f0", 0);
    model.study("std1").feature("param").setIndex("plistarr", "", 0);
    model.study("std1").feature("param").setIndex("punit", "Hz", 0);

//    In the table, click to select the cell at row number 1 and column number 2.
//    Click Range.
//    In the Range dialog, choose ISO preferred frequencies from the Entry method list.
//    In the Start frequency text field, type 125.
//    In the Stop frequency text field, type 8000.
//    Click Replace.

    model.study("std1").feature("param").setIndex("plistarr", "{125, 250, 500, 1e3, 2e3, 4e3, 8e3}", 0);

//    Solving the model takes a couple of minutes and uses less than 4 GB of RAM (depending on your hardware). This will increase for an increasing number of rays.
//    In the Study toolbar, click Compute.

    model.study("std1").createAutoSequences("all");

    model.sol().create("sol2");
    model.sol("sol2").study("std1");
    model.sol("sol2").label("Parametric Solutions 1");

    model.batch("p1").feature("so1").set("psol", "sol2");
    model.batch("p1").run("compute");

    model.result().dataset().create("ray1", "Ray");
    model.result().dataset("ray1").set("solution", "sol2");
    model.result().dataset("ray1").set("posdof", new String[]{"comp1.qx", "comp1.qy", "comp1.qz"});
    model.result().dataset("ray1").set("geom", "geom1");
    model.result().dataset("ray1").set("rgeom", "pgeom_rac");
    model.result().dataset("ray1").set("rgeomspec", "fromphysics");
    model.result().dataset("ray1").set("physicsinterface", "rac");
    model.result().create("pg1", "PlotGroup3D");
    model.result("pg1").set("data", "ray1");
    model.result("pg1").setIndex("looplevel", 7, 1);
    model.result("pg1").label("Ray Trajectories (rac)");
    model.result("pg1").set("showlegendsunit", true);
    model.result("pg1").create("rtrj1", "RayTrajectories");
    model.result("pg1").feature("rtrj1").set("linetype", "line");
    model.result("pg1").feature("rtrj1").create("col1", "Color");
    model.result("pg1").feature("rtrj1").feature("col1").set("expr", "rac.I");
    model.result("pg1").feature("rtrj1").create("filt1", "RayTrajectoriesFilter");
    model.result().dataset().create("re1", "Receiver3D");
    model.result().dataset("re1").set("data", "ray1");
    model.result().dataset("re1").set("receiverselection", "comp1.rac.rec1");
    model.result("pg1").run();

//    In the Settings window for 3D Plot Group, locate the Data section.
//    From the Time (s) list, select Interpolation.

    model.result("pg1").setIndex("looplevel", "interp", 0);

//    In the Time text field, type 10[ms].

    model.result("pg1").set("interp", new String[]{"10[ms]"});

//    In the Ray Trajectories (rac) toolbar, click Plot.

    model.result("pg1").run();
    model.result("pg1").run();

//    In the Model Builder window, expand the Ray Trajectories (rac) node, then click Ray Trajectories 1.
//    In the Settings window for Ray Trajectories, locate the Coloring and Style section.
//    Find the Line style subsection.
//    From the Type list, select None.

    model.result("pg1").feature("rtrj1").set("linetype", "none");

//    Find the Point style subsection.
//    From the Type list, select Point.

    model.result("pg1").feature("rtrj1").set("pointtype", "point");
    model.result("pg1").run();

//    In the Model Builder window, expand the Ray Trajectories 1 node, then click Color Expression 1.
//    In the Settings window for Color Expression, locate the Expression section.
//    In the Expression text field, type rac.Lp.

    model.result("pg1").feature("rtrj1").feature("col1").set("expr", "rac.Lp");

//    In the Ray Trajectories (rac) toolbar, click Plot.

    model.result("pg1").run();
    model.result("pg1").run();

//    In the Model Builder window, under Results, click Ray Trajectories (rac).
//    In the Settings window for 3D Plot Group, locate the Data section.
//    In the Time text field, type 20[ms].

    model.result("pg1").set("interp", new String[]{"20[ms]"});

//    In the Ray Trajectories (rac) toolbar, click Plot.

    model.result("pg1").run();

//    Create an animation to visualize early reflections and wave patterns.
//    In the Results toolbar, click Animation and choose Player.

    model.result().export().create("anim1", "Animation");
    model.result().export("anim1").set("target", "player");
    model.result().export("anim1").set("fontsize", "9");
    model.result().export("anim1").set("colortheme", "globaltheme");
    model.result().export("anim1").set("customcolor", new double[]{1, 1, 1});
    model.result().export("anim1").set("background", "color");
    model.result().export("anim1").set("gltfincludelines", "on");
    model.result().export("anim1").set("title1d", "on");
    model.result().export("anim1").set("legend1d", "on");
    model.result().export("anim1").set("logo1d", "on");
    model.result().export("anim1").set("options1d", "on");
    model.result().export("anim1").set("title2d", "on");
    model.result().export("anim1").set("legend2d", "on");
    model.result().export("anim1").set("logo2d", "on");
    model.result().export("anim1").set("options2d", "off");
    model.result().export("anim1").set("title3d", "on");
    model.result().export("anim1").set("legend3d", "on");
    model.result().export("anim1").set("logo3d", "on");
    model.result().export("anim1").set("options3d", "off");
    model.result().export("anim1").set("axisorientation", "on");
    model.result().export("anim1").set("grid", "on");
    model.result().export("anim1").set("axes1d", "on");
    model.result().export("anim1").set("axes2d", "on");
    model.result().export("anim1").set("showgrid", "on");
    model.result().export("anim1").showFrame();

//    In the Settings window for Animation, locate the Animation Editing section.
//    From the Time selection list, select Interpolated.

    model.result().export("anim1").set("looplevelinput", "interp");

//    Click Range.
//    In the Range dialog, type 3[ms] in the Start text field.
//    In the Step text field, type 1[ms].
//    In the Stop text field, type 50[ms].
//    Click Replace.

    model.result().export("anim1").set("interp", "range(3[ms],1[ms],50[ms])");

//    In the Settings window for Animation, locate the Frames section.
//    In the Number of frames text field, type 48.

    model.result().export("anim1").set("maxframes", 48);

//    Click the Play button in the Graphics toolbar.

    model.result().export("anim1").run();

//    On the <l>Results</l> node select the following options to facilitate the postprocessing workflow.
//    In the Model Builder window, click Results.
//    In the Settings window for Results, locate the Update of Results section.
//    Select the Only plot when requested checkbox.

    model.result().setOnlyPlotWhenRequested(true);

//    Select the Recompute all plot data after solving checkbox.
//    Locate the Save Data in the Model section.
//    From the Save plot data list, select On.
//    Also turn on the <l>Plot Information Section</l> to display rendering time and other useful information. This option applies to the whole COMSOL installation; if selected, the <l>Plot Information Section</l> will also appear in other models opened at a later stage.
//    Click the Show More Options button in the Model Builder toolbar.
//    In the Show More Options dialog, select Results > Information Section in the tree.
//    In the tree, select the checkbox for the Results > Information Section node.
//    Click OK.
//    In the Model Builder window, expand the Results > Datasets node, then click Receiver 3D 1.
//    In the Settings window for Receiver 3D, type Receiver 3D - All Bands in the Label text field.

    model.result().dataset("re1").label("Receiver 3D - All Bands");

//    In the Model Builder window, right-click Receiver 3D - All Bands and choose Duplicate.

    model.result().dataset().duplicate("re2", "re1");

//    In the Settings window for Receiver 3D, type Receiver 3D - 125 Hz Band in the Label text field.

    model.result().dataset("re2").label("Receiver 3D - 125 Hz Band");

//    Locate the Data section.
//    From the Parameter selection (f0) list, select From list.

    model.result().dataset("re2").setIndex("looplevelinput", "manual", 1);

//    In the Parameter values (f0 (Hz)) list, select 125.

    model.result().dataset("re2").setIndex("looplevel", new int[]{1}, 1);

//    select 125 in the Parameter values (f0 (Hz)) list.
//    In the Model Builder window, right-click Receiver 3D - 125 Hz Band and choose Duplicate.

    model.result().dataset().duplicate("re3", "re2");

//    In the Settings window for Receiver 3D, type Receiver 3D - 8 kHz Band in the Label text field.

    model.result().dataset("re3").label("Receiver 3D - 8 kHz Band");

//    Locate the Data section.
//    From the Parameter selection (f0) list, select From list.
//    In the Parameter values (f0 (Hz)) list, select 8000.

    model.result().dataset("re3").setIndex("looplevel", new int[]{7}, 1);

//    select 8000 in the Parameter values (f0 (Hz)) list.
//    In the Results toolbar, click 1D Plot Group.

    model.result().create("pg2", "PlotGroup1D");

//    In the Settings window for 1D Plot Group, type Impulse Response in the Label text field.

    model.result("pg2").label("Impulse Response");

//    Locate the Data section.
//    From the Dataset list, select Receiver 3D - All Bands.

    model.result("pg2").set("data", "re1");

//    In the Impulse Response toolbar, click More Plots and choose Impulse Response.

    model.result("pg2").create("imp1", "ImpulseResponse");
    model.result("pg2").feature("imp1").set("markerpos", "datapoints");
    model.result("pg2").feature("imp1").set("linewidth", "preference");

//    To get sharper filters you can modify the settings in the <l>Advanced</l> section.
//    In the Settings window for Impulse Response, click to expand the Advanced section.
//    In the \[N_p\] text field, type 22050.

    model.result("pg2").feature("imp1").set("zeropadding", 22050);

//    In the \[\delta\] text field, type 0.001.

    model.result("pg2").feature("imp1").set("ripplefactor", 0.001);

//    In the Impulse Response toolbar, click Plot.

    model.result("pg2").run();

//    Right-click Impulse Response 1 and choose Add Plot Data to Export.

    model.result().export().create("plot1", "pg2", "imp1", "Plot");

//    In the Settings window for Plot, locate the Output section.
//    From the File type list, select WAV audio file (*.wav; *.wave).

    model.result().export("plot1").set("exporttype", "wav");

//    In the Filename text field, type small_concert_hall_impulse_response.wav.

    model.result().export("plot1").set("filename", "small_concert_hall_impulse_response.wav");

//    Click to expand the Advanced section.
//    From the Encoding list, select 16-bit.

    model.result().export("plot1").set("quantlevel", "16bit");

//    Click <l>Export</l> to produce a .wav file of the impulse response, which could be used for auralization or analysis. Remember to disable any <l>Energy Decay</l> subfeature before exporting.
//    Proceed to analyze the impulse response with the <l>Energy Decay</l> subfeature. This will create a plot of the level/energy decay and a table with the objective quality metrics.
//    In the Model Builder window, expand the Results > Impulse Response node.
//    Right-click Impulse Response 1 and choose Energy Decay.

    model.result("pg2").feature("imp1").create("enyd1", "EnergyDecay");

//    In the Settings window for Energy Decay, locate the Display section.
//    From the Band type list, select Individual bands.

    model.result("pg2").feature("imp1").feature("enyd1").set("bandtype", "indiband");

//    From the Band frequency list, select All frequencies.

    model.result("pg2").feature("imp1").feature("enyd1").set("bandfreq", "All");

//    From the Plot list, select Level decay.

    model.result("pg2").feature("imp1").feature("enyd1").set("plot", "leveldecay");

//    Locate the Table section.
//    Find the Early energy subsection.
//    Clear the C₅₀ , Clarity checkbox.

    model.result("pg2").feature("imp1").feature("enyd1").set("c50", false);

//    Clear the tᵣ , First ray arrival time checkbox.

    model.result("pg2").feature("imp1").feature("enyd1").set("tr", false);

//    Find the Speech intelligibility subsection.
//    Clear the SNR, Apparent SNR checkbox.

    model.result("pg2").feature("imp1").feature("enyd1").set("snr", false);

//    Click the Show Legends button in the Graphics toolbar.

    model.result("pg2").feature("imp1").set("legend", true);

//    In the Impulse Response toolbar, click Plot.

    model.result("pg2").run();

//    To show the impulse response signal again, simply disable the <l>Energy Decay</l> subfeature and click <l>Plot</l>.
//    For the sake of this tutorial, the impulse response is imported and a Fourier transform of the transient signal is performed to obtain the frequency response of the room. Generally speaking, it would be more straightforward to disable the <l>Energy Decay</l> subfeature and apply the Fourier transform to the already existing plot.
//    In the Home toolbar, click Functions and choose Global > Interpolation.

    model.func().create("int4", "Interpolation");

//    In the Settings window for Interpolation, locate the Definition section.
//    From the Data source list, select File.

    model.func("int4").set("source", "file");

//    Click Browse.
//    Browse to the model's Application Library folder and double-click the file small_concert_hall_impulse_response.wav.

    model.func("int4").set("filename", "small_concert_hall_impulse_response.wav");

//    Find the Functions subsection.
//    In the table, enter the following settings:

    model.func("int4").setIndex("funcnametable", "IR_import", 0, 0);
    model.func("int4").setIndex("fununit", "Pa", 0);

//    Locate the Units section.
//    In the Function table, enter the following settings:

    model.func("int4").setIndex("argunit", "s", 0);

//    In the Argument table, enter the following settings:
//    Update the solution of the study to include the interpolation function newly created.
//    In the Study toolbar, click Update Solution.

    model.sol("sol1").updateSolution();
    model.sol("sol2").updateSolution();

//    In the Model Builder window, right-click Impulse Response and choose Duplicate.

    model.result().duplicate("pg3", "pg2");

//    In the Model Builder window, expand the Impulse Response 1 node.
//    In the Model Builder window, expand the Results > Impulse Response 1 > Impulse Response 1 node.
//    Right-click Energy Decay 1 and choose Disable.

    model.result("pg3").feature("imp1").feature("enyd1").active(false);

//    In the Model Builder window, under Results, click Impulse Response 1.
//    In the Settings window for 1D Plot Group, type Impulse Response FFT in the Label text field.

    model.result("pg3").label("Impulse Response FFT");

//    Locate the Axis section.
//    Select the x-axis log scale checkbox.

    model.result("pg3").set("xlog", true);

//    Locate the Legend section.
//    Clear the Show legends checkbox.

    model.result("pg3").set("showlegends", false);

//    When performing an FFT, the energy contained in the time signal is split between positive and negative frequencies. The <l>Show &gt; Frequency spectrum</l> option with <l>Scale &gt; Multiply by sampling period</l> applies the correct scaling factors to obtain physically meaningful results in dB for positive frequencies.
//    In the Model Builder window, click Impulse Response 1.
//    In the Settings window for Impulse Response, locate the Data section.
//    From the Source list, select Function.

    model.result("pg3").feature("imp1").set("source", "function");

//    From the Function list, select Interpolation 4 (IR_import).

    model.result("pg3").feature("imp1").set("function", "int4");

//    Locate the Expression section.
//    In the Expression text field, type IR_import(t).

    model.result("pg3").feature("imp1").set("funcexpr", "IR_import(t)");

//    Locate the x-Axis Data section.
//    From the Transformation list, select Discrete Fourier transform.

    model.result("pg3").feature("imp1").set("transform", "fourier");

//    From the Show list, select Frequency spectrum.

    model.result("pg3").feature("imp1").set("fouriershow", "spectrum");

//    From the Scale list, select Multiply by sampling period.

    model.result("pg3").feature("imp1").set("scale", "multiplyperiod");

//    Select the Frequency range checkbox.

    model.result("pg3").feature("imp1").set("freqrangeactive", true);

//    In the Minimum text field, type 100.

    model.result("pg3").feature("imp1").set("freqmin", 100);

//    In the Maximum text field, type 10000.

    model.result("pg3").feature("imp1").set("freqmax", 10000);

//    Select the In dB checkbox.

    model.result("pg3").feature("imp1").set("indb", true);

//    From the dB type list, select 20log.

    model.result("pg3").feature("imp1").set("dbtype", "20log");

//    From the dB reference list, select Manual.

    model.result("pg3").feature("imp1").set("dbref", "manual");

//    In the Reference value text field, type 20e-6.

    model.result("pg3").feature("imp1").set("dbmanualref", "20e-6");

//    In the Impulse Response FFT toolbar, click Plot.

    model.result("pg3").run();

//    This is the raw transfer function of the room (no smoothing).
//    In the Model Builder window, click Impulse Response 1.
//    Locate the Smoothing section.
//    Select the Moving average checkbox.

    model.result("pg3").feature("imp1").set("movingaverage", true);

//    From the Type list, select 1/n octave.

    model.result("pg3").feature("imp1").set("smoothtype", "octave");

//    In the n text field, type 3.

    model.result("pg3").feature("imp1").set("noctave", 3);

//    In the Impulse Response FFT toolbar, click Plot.

    model.result("pg3").run();

//    In the Results toolbar, click 3D Plot Group.

    model.result().create("pg4", "PlotGroup3D");

//    In the Settings window for 3D Plot Group, type Seats SPL in the Label text field.

    model.result("pg4").label("Seats SPL");

//    Locate the Data section.
//    From the Dataset list, select Study 1 - Omnidirectional Source/Parametric Solutions 1 (sol2).

    model.result("pg4").set("data", "dset2");

//    Locate the Color Legend section.
//    Select the Show units checkbox.

    model.result("pg4").set("showlegendsunit", true);

//    Right-click Seats SPL and choose Surface.

    model.result("pg4").create("surf1", "Surface");
    model.result("pg4").feature("surf1").set("evaluationsettings", "parent");

//    In the Settings window for Surface, click Replace Expression in the upper-right corner of the Expression section.
//    From the menu, choose Component 1 (comp1) > Ray Acoustics > Accumulated variables > Wall intensity comp1.rac.wall8.spl1.Iw > rac.wall8.spl1.Lp - Sound pressure level - dB.

    model.result("pg4").feature("surf1").set("expr", "rac.wall8.spl1.Lp");
    model.result("pg4").feature("surf1").set("descr", "Sound pressure level");

//    Locate the Expression section.
//    From the Unit list, select dB.

    model.result("pg4").feature("surf1").set("unit", "dB");

//    In the Seats SPL toolbar, click Plot.

    model.result("pg4").run();

//    In the Results toolbar, click 1D Plot Group.

    model.result().create("pg5", "PlotGroup1D");

//    In the Settings window for 1D Plot Group, type Reflectogram in the Label text field.

    model.result("pg5").label("Reflectogram");

//    Click to expand the Title section.
//    From the Title type list, select Label.

    model.result("pg5").set("titletype", "label");

//    Locate the Plot Settings section.
//    Select the x-axis label checkbox.

    model.result("pg5").set("xlabelactive", true);

//    In the associated text field, type t (s).

    model.result("pg5").set("xlabel", "t (s)");

    return model;
  }

  public static Model run3(Model model) {

//    Select the y-axis label checkbox.

    model.result("pg5").set("ylabelactive", true);

//    In the associated text field, type log10(Power).

    model.result("pg5").set("ylabel", "log10(Power)");

//    Locate the Data section.
//    From the Dataset list, select None.

    model.result("pg5").set("data", "none");

//    Locate the Axis section.
//    Select the y-axis log scale checkbox.

    model.result("pg5").set("ylog", true);

//    In the Reflectogram toolbar, click More Plots and choose Ray.

    model.result("pg5").create("rtp1", "Ray1D");
    model.result("pg5").feature("rtp1").set("markerpos", "datapoints");
    model.result("pg5").feature("rtp1").set("linewidth", "preference");

//    In the Settings window for Ray, locate the Data section.
//    From the Dataset list, select Receiver 3D - 125 Hz Band.

    model.result("pg5").feature("rtp1").set("data", "re2");

//    Locate the y-Axis Data section.
//    In the Expression text field, type re1dist*rac.Q/re1vol.

    model.result("pg5").feature("rtp1").set("expr", "re1dist*rac.Q/re1vol");

//    Click to expand the Coloring and Style section.
//    Find the Line style subsection.
//    From the Line list, select None.

    model.result("pg5").feature("rtp1").set("linestyle", "none");

//    Find the Line markers subsection.
//    From the Marker list, select Point.

    model.result("pg5").feature("rtp1").set("linemarker", "point");

//    Click to expand the Legends section.
//    From the Legends list, select Manual.

    model.result("pg5").feature("rtp1").set("legendmethod", "manual");

//    Select the Show legends checkbox.

    model.result("pg5").feature("rtp1").set("legend", true);

//    In the table, enter the following settings:

    model.result("pg5").feature("rtp1").setIndex("legends", "f<sub>c</sub> = 125 Hz", 0);

//    Right-click Ray 1 and choose Duplicate.

    model.result("pg5").feature().duplicate("rtp2", "rtp1");

//    In the Settings window for Ray, locate the Data section.
//    From the Dataset list, select Receiver 3D - 8 kHz Band.

    model.result("pg5").feature("rtp2").set("data", "re3");

//    Locate the Legends section.
//    In the table, enter the following settings:

    model.result("pg5").feature("rtp2").setIndex("legends", "f<sub>c</sub> = 8000 Hz", 0);

//    In the Reflectogram toolbar, click Plot.

    model.result("pg5").run();

//    In the Results toolbar, click 1D Plot Group.

    model.result().create("pg6", "PlotGroup1D");

//    In the Settings window for 1D Plot Group, type T60 - Estimates and Model in the Label text field.

    model.result("pg6").label("T60 - Estimates and Model");

//    Locate the Data section.
//    From the Dataset list, select Study 1 - Omnidirectional Source/Parametric Solutions 1 (sol2).

    model.result("pg6").set("data", "dset2");

//    From the Time selection list, select First.

    model.result("pg6").setIndex("looplevelinput", "first", 0);

//    Click to expand the Title section.
//    From the Title type list, select Label.

    model.result("pg6").set("titletype", "label");

//    Locate the Plot Settings section.
//    Select the x-axis label checkbox.

    model.result("pg6").set("xlabelactive", true);

//    In the associated text field, type f<sub>c</sub> (Hz).

    model.result("pg6").set("xlabel", "f<sub>c</sub> (Hz)");

//    Locate the Axis section.
//    Select the Manual axis limits checkbox.

    model.result("pg6").set("axislimits", true);

//    In the x minimum text field, type 120.

    model.result("pg6").set("xmin", 120);

//    In the x maximum text field, type 8322.

    model.result("pg6").set("xmax", 8322);

//    In the y minimum text field, type 0.

    model.result("pg6").set("ymin", 0);

//    In the y maximum text field, type 1.6.

    model.result("pg6").set("ymax", 1.6);

//    Select the x-axis log scale checkbox.

    model.result("pg6").set("xlog", true);

//    Locate the Legend section.
//    From the Position list, select Lower left.

    model.result("pg6").set("legendpos", "lowerleft");

//    Right-click T60 - Estimates and Model and choose Global.

    model.result("pg6").create("glob1", "Global");
    model.result("pg6").feature("glob1").set("markerpos", "datapoints");
    model.result("pg6").feature("glob1").set("linewidth", "preference");

//    In the Settings window for Global, locate the y-Axis Data section.
//    In the table, enter the following settings:

    model.result("pg6").feature("glob1").setIndex("expr", "T60_S", 0);
    model.result("pg6").feature("glob1").setIndex("unit", "s", 0);
    model.result("pg6").feature("glob1").setIndex("descr", "Reverberation time (Sabine)", 0);
    model.result("pg6").feature("glob1").setIndex("expr", "T60_Sna", 1);
    model.result("pg6").feature("glob1").setIndex("unit", "s", 1);
    model.result("pg6").feature("glob1").setIndex("descr", "Reverberation time (Sabine, no air absorption)", 1);
    model.result("pg6").feature("glob1").setIndex("expr", "T60_E", 2);
    model.result("pg6").feature("glob1").setIndex("unit", "s", 2);
    model.result("pg6").feature("glob1").setIndex("descr", "Reverberation time (Eyring)", 2);

//    Locate the x-Axis Data section.
//    From the Axis source data list, select f0.

    model.result("pg6").feature("glob1").set("xdatasolnumtype", "level2");

//    Click to expand the Coloring and Style section.
//    Find the Line markers subsection.
//    From the Marker list, select Star.

    model.result("pg6").feature("glob1").set("linemarker", "star");

//    In the Model Builder window, right-click T60 - Estimates and Model and choose Table Graph.

    model.result("pg6").create("tblp1", "Table");
    model.result("pg6").feature("tblp1").set("markerpos", "datapoints");
    model.result("pg6").feature("tblp1").set("linewidth", "preference");

//    In the Settings window for Table Graph, locate the Data section.
//    From the x-axis data list, select fc (Hz).

    model.result("pg6").feature("tblp1").set("xaxisdata", 1);

//    From the Plot columns list, select Manual.

    model.result("pg6").feature("tblp1").set("plotcolumninput", "manual");

//    In the Columns list, select T60 (s).

    model.result("pg6").feature("tblp1").set("plotcolumns", new int[]{8});

//    select T60 (s) in the Columns list.
//    Locate the Coloring and Style section.
//    Find the Line markers subsection.
//    From the Marker list, select Circle.

    model.result("pg6").feature("tblp1").set("linemarker", "circle");

//    Click to expand the Legends section.
//    Select the Show legends checkbox.

    model.result("pg6").feature("tblp1").set("legend", true);

//    Find the Prefix and suffix subsection.
//    In the Suffix text field, type - Ray acoustics.

    model.result("pg6").feature("tblp1").set("legendsuffix", " - Ray acoustics");

//    In the T60 - Estimates and Model toolbar, click Plot.

    model.result("pg6").run();

//    In the Results toolbar, click 1D Plot Group.

    model.result().create("pg7", "PlotGroup1D");

//    In the Settings window for 1D Plot Group, type Definition in the Label text field.

    model.result("pg7").label("Definition");

//    Locate the Data section.
//    From the Dataset list, select Study 1 - Omnidirectional Source/Parametric Solutions 1 (sol2).

    model.result("pg7").set("data", "dset2");

//    From the Time selection list, select First.

    model.result("pg7").setIndex("looplevelinput", "first", 0);

//    Click to expand the Title section.
//    From the Title type list, select Label.

    model.result("pg7").set("titletype", "label");

//    Locate the Plot Settings section.
//    Select the x-axis label checkbox.

    model.result("pg7").set("xlabelactive", true);

//    In the associated text field, type f<sub>c</sub> (Hz).

    model.result("pg7").set("xlabel", "f<sub>c</sub> (Hz)");

//    Select the y-axis label checkbox.

    model.result("pg7").set("ylabelactive", true);

//    In the associated text field, type D (%).

    model.result("pg7").set("ylabel", "D (%)");

//    Locate the Axis section.
//    Select the Manual axis limits checkbox.

    model.result("pg7").set("axislimits", true);

//    In the x minimum text field, type 120.

    model.result("pg7").set("xmin", 120);

//    In the x maximum text field, type 8322.

    model.result("pg7").set("xmax", 8322);

//    In the y minimum text field, type 0.

    model.result("pg7").set("ymin", 0);

//    In the y maximum text field, type 100.

    model.result("pg7").set("ymax", 100);

//    Select the x-axis log scale checkbox.

    model.result("pg7").set("xlog", true);

//    Locate the Legend section.
//    From the Position list, select Upper left.

    model.result("pg7").set("legendpos", "upperleft");

//    Right-click Definition and choose Global.

    model.result("pg7").create("glob1", "Global");
    model.result("pg7").feature("glob1").set("markerpos", "datapoints");
    model.result("pg7").feature("glob1").set("linewidth", "preference");

//    In the Settings window for Global, locate the y-Axis Data section.
//    In the table, enter the following settings:

    model.result("pg7").feature("glob1").setIndex("expr", "D", 0);
    model.result("pg7").feature("glob1").setIndex("unit", "s", 0);
    model.result("pg7").feature("glob1").setIndex("descr", "Definition estimate", 0);

//    Locate the x-Axis Data section.
//    From the Axis source data list, select f0.

    model.result("pg7").feature("glob1").set("xdatasolnumtype", "level2");

//    Click to expand the Coloring and Style section.
//    Find the Line markers subsection.
//    From the Marker list, select Star.

    model.result("pg7").feature("glob1").set("linemarker", "star");

//    In the Model Builder window, right-click Definition and choose Table Graph.

    model.result("pg7").create("tblp1", "Table");
    model.result("pg7").feature("tblp1").set("markerpos", "datapoints");
    model.result("pg7").feature("tblp1").set("linewidth", "preference");

//    In the Settings window for Table Graph, locate the Data section.
//    From the x-axis data list, select fc (Hz).

    model.result("pg7").feature("tblp1").set("xaxisdata", 1);

//    From the Plot columns list, select Manual.

    model.result("pg7").feature("tblp1").set("plotcolumninput", "manual");

//    In the Columns list, select D (%).

    model.result("pg7").feature("tblp1").set("plotcolumns", new int[]{2});

//    select D (%) in the Columns list.
//    Locate the Coloring and Style section.
//    Find the Line markers subsection.
//    From the Marker list, select Circle.

    model.result("pg7").feature("tblp1").set("linemarker", "circle");

//    Click to expand the Legends section.
//    Select the Show legends checkbox.

    model.result("pg7").feature("tblp1").set("legend", true);

//    Find the Prefix and suffix subsection.
//    In the Suffix text field, type - Ray acoustics.

    model.result("pg7").feature("tblp1").set("legendsuffix", " - Ray acoustics");

//    In the Definition toolbar, click Plot.

    model.result("pg7").run();

//    Right-click Definition and choose Duplicate.

    model.result().duplicate("pg8", "pg7");

//    In the Settings window for 1D Plot Group, type Clarity in the Label text field.

    model.result("pg8").label("Clarity");

//    Locate the Plot Settings section.
//    In the y-axis label text field, type C80 (dB).

    model.result("pg8").set("ylabel", "C80 (dB)");

//    Locate the Axis section.
//    In the x minimum text field, type 120.

    model.result("pg8").set("xmin", 120);

//    In the x maximum text field, type 8322.

    model.result("pg8").set("xmax", 8322);

//    In the y minimum text field, type -1.

    model.result("pg8").set("ymin", -1);

//    In the y maximum text field, type 10.

    model.result("pg8").set("ymax", 10);

//    In the Model Builder window, expand the Clarity node, then click Global 1.
//    In the Settings window for Global, locate the y-Axis Data section.
//    In the table, enter the following settings:

    model.result("pg8").feature("glob1").setIndex("expr", "C80", 0);
    model.result("pg8").feature("glob1").setIndex("unit", "", 0);
    model.result("pg8").feature("glob1").setIndex("descr", "Clarity 80 estimate", 0);

//    In the Model Builder window, click Table Graph 1.
//    In the Settings window for Table Graph, locate the Data section.
//    In the Columns list, select C80 (dB).

    model.result("pg8").feature("tblp1").set("plotcolumns", new int[]{3});

//    select C80 (dB) in the Columns list.
//    In the Clarity toolbar, click Plot.

    model.result("pg8").run();

//    In the Model Builder window, right-click Clarity and choose Duplicate.

    model.result().duplicate("pg9", "pg8");

//    In the Settings window for 1D Plot Group, type Center Time in the Label text field.

    model.result("pg9").label("Center Time");

//    Locate the Plot Settings section.
//    In the y-axis label text field, type ts (s).

    model.result("pg9").set("ylabel", "ts (s)");

//    Locate the Axis section.
//    In the x minimum text field, type 120.

    model.result("pg9").set("xmin", 120);

//    In the x maximum text field, type 8322.

    model.result("pg9").set("xmax", 8322);

//    In the y minimum text field, type 0.

    model.result("pg9").set("ymin", 0);

//    In the y maximum text field, type 0.15.

    model.result("pg9").set("ymax", 0.15);

//    Locate the Legend section.
//    From the Position list, select Lower left.

    model.result("pg9").set("legendpos", "lowerleft");

//    In the Model Builder window, expand the Center Time node, then click Global 1.
//    In the Settings window for Global, locate the y-Axis Data section.
//    In the table, enter the following settings:

    model.result("pg9").feature("glob1").setIndex("expr", "ts", 0);
    model.result("pg9").feature("glob1").setIndex("unit", "", 0);
    model.result("pg9").feature("glob1").setIndex("descr", "Center time estimate", 0);

//    In the Model Builder window, click Table Graph 1.
//    In the Settings window for Table Graph, locate the Data section.
//    In the Columns list, select ts (s).

    model.result("pg9").feature("tblp1").set("plotcolumns", new int[]{4});

//    select ts (s) in the Columns list.
//    In the Center Time toolbar, click Plot.

    model.result("pg9").run();

//    In the Model Builder window, right-click Center Time and choose Duplicate.

    model.result().duplicate("pg10", "pg9");

//    In the Settings window for 1D Plot Group, type Reverberation Times in the Label text field.

    model.result("pg10").label("Reverberation Times");

//    Locate the Plot Settings section.
//    In the y-axis label text field, type RT (s).

    model.result("pg10").set("ylabel", "RT (s)");

//    Locate the Axis section.
//    In the x minimum text field, type 120.

    model.result("pg10").set("xmin", 120);

//    In the x maximum text field, type 8322.

    model.result("pg10").set("xmax", 8322);

//    In the y minimum text field, type 0.
//    In the y maximum text field, type 1.6.

    model.result("pg10").set("ymax", 1.6);

//    In the Model Builder window, expand the Reverberation Times node.
//    Right-click Global 1 and choose Delete.

    model.result("pg10").feature().remove("glob1");

//    In the Settings window for Table Graph, locate the Data section.
//    In the Columns list, select EDT (s), T20 (s), T30 (s), T60 (s).

    model.result("pg10").feature("tblp1").set("plotcolumns", new int[]{5, 6, 7, 8});

//    In the Reverberation Times toolbar, click Plot.

    model.result("pg10").run();

//    In the Model Builder window, right-click Reverberation Times and choose Duplicate.

    model.result().duplicate("pg11", "pg10");

//    In the Settings window for 1D Plot Group, type Speech Transmission Index in the Label text field.

    model.result("pg11").label("Speech Transmission Index");

//    Locate the Plot Settings section.
//    In the y-axis label text field, type STI (1).

    model.result("pg11").set("ylabel", "STI (1)");

//    Locate the Axis section.
//    In the x minimum text field, type 120.

    model.result("pg11").set("xmin", 120);

//    In the x maximum text field, type 8322.

    model.result("pg11").set("xmax", 8322);

//    In the y minimum text field, type 0.
//    In the y maximum text field, type 1.

    model.result("pg11").set("ymax", 1);

//    Locate the Legend section.
//    From the Position list, select Upper left.

    model.result("pg11").set("legendpos", "upperleft");

//    In the Model Builder window, expand the Speech Transmission Index node, then click Table Graph 1.
//    In the Settings window for Table Graph, locate the Data section.
//    In the Columns list, select STI (1).

    model.result("pg11").feature("tblp1").set("plotcolumns", new int[]{9});

//    select STI (1) in the Columns list.
//    In the Speech Transmission Index toolbar, click Plot.

    model.result("pg11").run();

//    In the Model Builder window, under Results, Ctrl-click to select Definition, Clarity, Center Time, Reverberation Times, Speech Transmission Index.
//    Right-click and choose Group.

    model.nodeGroup().create("grp1", "Results");
    model.nodeGroup("grp1").set("type", "plotgroup");
    model.nodeGroup("grp1").placeAfter("plotgroup", "pg6");
    model.nodeGroup("grp1").add("plotgroup", "pg7");
    model.nodeGroup("grp1").add("plotgroup", "pg8");
    model.nodeGroup("grp1").add("plotgroup", "pg9");
    model.nodeGroup("grp1").add("plotgroup", "pg10");
    model.nodeGroup("grp1").add("plotgroup", "pg11");

//    In the Settings window for Group, type Objective Quality Metric Plots in the Label text field.

    model.nodeGroup("grp1").label("Objective Quality Metric Plots");

//    Next, solve the model with the directional loudspeaker using a parametric sweep that fits the frequency range of the speaker data.
//    In the Home toolbar, click Add Study to open the Add Study window.
//    Find the Studies subsection.
//    In the Select Study tree, select Preset Studies for Selected Physics Interfaces > Ray Tracing.
//    Click Add Study in the window toolbar.

    model.study().create("std2");
    model.study("std2").create("rtrac", "RayTracing");

//    In the Home toolbar, click Add Study to close the Add Study window.
//    In the Settings window for Study, type Study 2 - Directional Loudspeaker in the Label text field.

    model.study("std2").label("Study 2 - Directional Loudspeaker");

//    In the Model Builder window, under Study 2 - Directional Loudspeaker, click Step 1: Ray Tracing.
//    In the Settings window for Ray Tracing, locate the Study Settings section.
//    From the Time unit list, select s.

    model.study("std2").feature("rtrac").set("tunit", "s");

//    In the Output times text field, type 0 1.6.

    model.study("std2").feature("rtrac").set("tlist", "0 1.6");

//    Locate the Physics and Variables Selection section.
//    Select the Modify model configuration for study step checkbox.

    model.study("std2").feature("rtrac").set("useadvanceddisable", true);

//    In the tree, select Component 1 (comp1) > Ray Acoustics (rac) > Source with Directivity 1.
//    Click Disable.

    model.study("std2").feature("rtrac").set("disabledphysics", new String[]{"rac/swd1"});

//    In the Study toolbar, click Parametric Sweep.

    model.study("std2").create("param", "Parametric");

//    In the Settings window for Parametric Sweep, locate the Study Settings section.
//    Click Add.

    model.study("std2").feature("param").setIndex("pname", "alpha0", 0);
    model.study("std2").feature("param").setIndex("plistarr", "", 0);
    model.study("std2").feature("param").setIndex("punit", "rad", 0);
    model.study("std2").feature("param").setIndex("pname", "alpha0", 0);
    model.study("std2").feature("param").setIndex("plistarr", "", 0);
    model.study("std2").feature("param").setIndex("punit", "rad", 0);

//    In the table, enter the following settings:

    model.study("std2").feature("param").setIndex("pname", "f0", 0);
    model.study("std2").feature("param").setIndex("plistarr", "", 0);
    model.study("std2").feature("param").setIndex("punit", "Hz", 0);

//    In the table, click to select the cell at row number 1 and column number 2.
//    Click Range.
//    In the Range dialog, choose ISO preferred frequencies from the Entry method list.
//    In the Start frequency text field, type 63.
//    In the Stop frequency text field, type 4000.
//    Click Replace.

    model.study("std2").feature("param").setIndex("plistarr", "{63, 125, 250, 500, 1e3, 2e3, 4e3}", 0);

//    In the Study toolbar, click Compute.

    model.study("std2").createAutoSequences("all");

    model.sol().create("sol11");
    model.sol("sol11").study("std2");
    model.sol("sol11").label("Parametric Solutions 2");

    model.batch("p2").feature("so1").set("psol", "sol11");
    model.batch("p2").run("compute");

    model.result().dataset().create("ray2", "Ray");
    model.result().dataset("ray2").set("solution", "sol11");
    model.result().dataset("ray2").set("posdof", new String[]{"comp1.qx", "comp1.qy", "comp1.qz"});
    model.result().dataset("ray2").set("geom", "geom1");
    model.result().dataset("ray2").set("rgeom", "pgeom_rac");
    model.result().dataset("ray2").set("rgeomspec", "fromphysics");
    model.result().dataset("ray2").set("physicsinterface", "rac");
    model.result().create("pg12", "PlotGroup3D");
    model.result("pg12").set("data", "ray2");
    model.result("pg12").setIndex("looplevel", 7, 1);
    model.result("pg12").label("Ray Trajectories (rac) 1");
    model.result("pg12").set("showlegendsunit", true);
    model.result("pg12").create("rtrj1", "RayTrajectories");
    model.result("pg12").feature("rtrj1").set("linetype", "line");
    model.result("pg12").feature("rtrj1").create("col1", "Color");
    model.result("pg12").feature("rtrj1").feature("col1").set("expr", "rac.I");
    model.result("pg12").feature("rtrj1").create("filt1", "RayTrajectoriesFilter");
    model.result().dataset().create("re4", "Receiver3D");
    model.result().dataset("re4").set("data", "ray2");
    model.result().dataset("re4").set("receiverselection", "comp1.rac.rec1");
    model.result("pg12").set("boxlengths", new double[]{11.000000000000002, 10.000000000000002, 7.460579422167753});
    model.result("pg12").feature("rtrj1").set("sphereradiusscale", 1);
    model.result("pg12").feature("rtrj1").set("sphereradiusscaleactive", false);
    model.result("pg12").feature("rtrj1").set("tailscale", 1);
    model.result("pg12").feature("rtrj1").set("tailscaleactive", false);
    model.result("pg12").feature("rtrj1").set("arrowscale", 0);
    model.result("pg12").feature("rtrj1").set("arrowscaleactive", false);
    model.result("pg12").feature("rtrj1").set("ellipsearrowscale", 1);
    model.result("pg12").feature("rtrj1").set("ellipsearrowscaleactive", false);
    model.result("pg12").feature("rtrj1").feature("col1").set("rangeunit", "W/m^2");
    model.result("pg12").feature("rtrj1").feature("col1").set("rangecolormin", 2.0503783746629025E-26);
    model.result("pg12").feature("rtrj1").feature("col1").set("rangecolormax", 6.173703699169504E9);
    model.result("pg12").feature("rtrj1").feature("col1").set("rangecoloractive", "off");
    model.result("pg12").feature("rtrj1").feature("col1")
         .set("rangeactualminmax", new double[]{2.0503783746629025E-26, 6.173703699169504E9});
    model.result("pg12").feature("rtrj1").feature("col1").set("rangeisshared", false);
    model.result("pg12").feature("rtrj1").feature("col1").set("rangeminpositive", 2.0503783746629025E-26);
    model.result("pg12").feature("rtrj1").feature("col1").set("rangedatamin", 2.0503783746629025E-26);
    model.result("pg12").feature("rtrj1").feature("col1").set("rangedatamax", 6.173703699169504E9);
    model.result("pg12").feature("rtrj1").feature("col1").set("rangedataactive", "off");
    model.result("pg12").feature("rtrj1").set("renderinfo", "1 Edge3D 1 1 4 1 Color");
    model.result("pg12").feature("rtrj1")
         .set("boxlengths", new double[]{11.550000190734863, 9.999887466430664, 7.460576057434082});

//    In the Settings window for 3D Plot Group, locate the Data section.
//    From the Time (s) list, select Interpolation.

    model.result("pg12").setIndex("looplevel", "interp", 0);

//    In the Time text field, type 1[ms].

    model.result("pg12").set("interp", new String[]{"1[ms]"});

//    In the Model Builder window, expand the Ray Trajectories (rac) 1 node, then click Ray Trajectories 1.
//    In the Settings window for Ray Trajectories, locate the Coloring and Style section.
//    Find the Line style subsection.
//    From the Type list, select None.

    model.result("pg12").feature("rtrj1").set("linetype", "none");

//    Find the Point style subsection.
//    From the Type list, select Point.

    model.result("pg12").feature("rtrj1").set("pointtype", "point");

//    In the Model Builder window, expand the Ray Trajectories 1 node, then click Color Expression 1.
//    In the Settings window for Color Expression, locate the Expression section.
//    In the Expression text field, type rac.Lp.

    model.result("pg12").feature("rtrj1").feature("col1").set("expr", "rac.Lp");

//    In the Ray Trajectories (rac) 1 toolbar, click Plot.

    model.result("pg12").run();

//    In the Home toolbar, click Add Plot Group and choose 3D Plot Group.

    model.result().create("pg13", "PlotGroup3D");

//    In the Settings window for 3D Plot Group, type Loudspeaker Orientation in the Label text field.

    model.result("pg13").label("Loudspeaker Orientation");

//    Locate the Data section.
//    From the Dataset list, select Study 2 - Directional Loudspeaker/Solution 10 (sol10).

    model.result("pg13").set("data", "dset3");

//    Click to expand the Selection section.
//    From the Geometric entity level list, select Point.

    model.result("pg13").selection().geom("geom1", 0);

//    Select Point 11.

    model.result("pg13").selection().set(11);

//    In the Loudspeaker Orientation toolbar, click More Plots and choose Coordinate System Point.

    model.result("pg13").create("sysp1", "CoordSysPoint");

//    In the Settings window for Coordinate System Point, locate the Coordinate System section.
//    From the Coordinate system list, select Rotated System 2 (sys2).

    model.result("pg13").feature("sysp1").set("sys", "sys2");

//    Locate the Coloring and Style section.
//    Select the Scale factor checkbox.

    model.result("pg13").feature("sysp1").set("scaleactive", true);

//    In the associated text field, type 2.

    model.result("pg13").feature("sysp1").set("scale", 2);

//    In the Loudspeaker Orientation toolbar, click Plot.

    model.result("pg13").run();

//    In the Model Builder window, right-click Seats SPL and choose Duplicate.

    model.result().duplicate("pg14", "pg4");

//    In the Settings window for 3D Plot Group, locate the Data section.
//    From the Dataset list, select Study 2 - Directional Loudspeaker/Parametric Solutions 2 (sol11).

    model.result("pg14").set("data", "dset4");

//    In the Seats SPL 1 toolbar, click Plot.

    model.result("pg14").run();

    model.title("Small Concert Hall Acoustics");

    model
         .description("Designing structures and open spaces with respect to sound quality is important for concert halls, outdoor environments, and even the rooms of a house. Simulating acoustics in the high-frequency limit, where the wavelength is smaller than the geometrical features, is best done with ray acoustics.\n\nThis tutorial model shows the basic steps and principles used when setting up a model using the Ray Acoustics physics interface. In the model, the acoustics of a small concert hall is analyzed. The model setup includes an omnidirectional sound source, wall boundary conditions for specular and diffuse scattering, sound pressure evaluation, a receiver dataset used for an impulse response plot, and an energy reflectogram. The results are compared to simple reverberation time estimates.");

    return model;
  }

  public static void main(String[] args) {
    Model model = run();
    model = run2(model);
    run3(model);
  }

}
