<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
 A simple SEA model of two rooms with a dividing wall
In this notebook we create a simple SEA model of two rooms divided by a concrete wall.
We start by importing some of the modules that are needed.
Step1:  Creating a SEA model
To create a SEA model we begin by creating an instance of System.
Step2:  We are only interested in a limited frequency range, e.g. the third octave bands ranging from 1000 to 4000 Hz.
Materials
The rooms are filled with air, so we add air as material.
Step3:  We don't know the shear modulus of concrete, so let's calculate it. With the function modulus we can calculate for an isotropic material any elastic modulus given two other ones.
Step4:  Just to be sure, we can list the properties of the concrete.
Step5:  Rooms and wall
Now we add the two rooms.
Step6:  Given the material type and the volume we can for example calculate the mass of the air in the room
Step7:  or plot the modal density of the subsystem representing longitudinal waves
Step8:  We now add the concrete wall.
Step9:  Let's have a look at the modal densities of the subsystems.
Step10:  The modal density of the subsystem representing bending waves in the wall seems to remain constant.
It's also possible to inspect objects further. For example, as was shown with the mass of the room, it is possible to request e.g. multiple parameters.
Step11:  Shown is now a table, but what is returned is in fact a pandas DataFrame. Pandas is a data analysis toolkit and offers powerful tools to analyse data and to export data to e.g. spreadsheet formats like Excel.
Junction
The rooms and the wall form a junction and connect along a surface.
Step12:  Now, when we call junction1.update_couplings it tries to determine all the couplings between the subsystems of the components that were added.
Step13:  We can now for example see the coupling loss factors of all the couplings that were added.
Step14:  Now that both the coupling loss factors and damping loss factors are known we can also list the total loss factor
Step15:  The coupling loss factor of the coupling between the rooms is based on the non-resonant transmission coefficient.
Step16:  Excitation
We have defined the subsystems and couplings. What's left is to add an excitation to the system.
Step17:  The input power $P$ depends on the volume velocity $U$ of the source and the real part of the radiation impedance, i.e. the radiation resistance $R$.
Step18:  The resistance increases with frequency and therefore the radiated power increases similary.
Step19:  Solving the system
Now we can solve the system.
Step20:  We can have a look at the modal energy
Step21:  but those values are generally hard to interpret. Instead, we could just request the sound pressure levels in the rooms
Step22:  or plot them.
Step23:  Let's consider the sound pressure level difference between the two rooms.
Step24:  Obviously, we can also look at the modal energies
Step25:  or see the level contributions of the individual subsystems.
Step26:  Path analysis and graphs
All the objects in SeaPy remember to which other objects they're connected. For example, we can list the subsystems in a component.
Step27:  As soon as a model gets a bit bigger it can be hard to track which objects are connected. One way to help with keeping an overview is by drawing graphs.
Step28:  The following graph shows the relation between components and subsystems.
Step29:  We can also show for example subsystems and couplings.
Step30:  Path analysis
By creating graphs of subsystems and couplings it is also straightforward to check whether subsystems are in anyway connected
Step31:  and to determine the possible paths between any two subsystems.
Step32:  We can also calculate the level difference due to a transmission path.
Step33:  Saving and restoring a model
SEA models can be saved as YAML.
Step34:  YAML is a human-readable file format. Models can be implemented or edited in the YAML file if desired.
Step35:  Loading is done using the load method.
Step36:  To verify whether the models are similar we check the modal energy.
Step37:  That looks correctly. To be really sure we just calculate the modal energies again in the second model, to verify that other parameters have also been restored.
Step38:  Same results.
Source code and documentation
Source code of seapy can be found at GitHub and documentation right here.
<ASSISTANT_TASK:>
Python Code:
import numpy as np
import pandas as pd
pd.set_option('float_format', '{:.2e}'.format)
import matplotlib
%matplotlib inline
Explanation: A simple SEA model of two rooms with a dividing wall
In this notebook we create a simple SEA model of two rooms divided by a concrete wall.
We start by importing some of the modules that are needed.
End of explanation
from seapy import System
from acoustics.signal import OctaveBand
f = OctaveBand(fstart=20.0, fstop=4000.0, fraction=1)
system1 = System(f)
Explanation: Creating a SEA model
To create a SEA model we begin by creating an instance of System.
End of explanation
air = system1.add_material('air', 
                           'MaterialGas',
                           density = 1.296,
                           temperature = 293.0,
                           bulk = 1.01e5,
                           loss_factor=0.05)
concrete = system1.add_material('concrete', 
                                'MaterialSolid', 
                                young=3.0e10, 
                                poisson=0.15,
                                density=2.3e3,
                                loss_factor=0.02)
Explanation: We are only interested in a limited frequency range, e.g. the third octave bands ranging from 1000 to 4000 Hz.
Materials
The rooms are filled with air, so we add air as material.
End of explanation
from seapy.materials.materialsolid import modulus
concrete.shear = modulus('shear', young=3.0e10, poisson=0.15)
Explanation: We don't know the shear modulus of concrete, so let's calculate it. With the function modulus we can calculate for an isotropic material any elastic modulus given two other ones.
End of explanation
concrete.info(['density',
               'poisson',
               'young',
               'shear',])
Explanation: Just to be sure, we can list the properties of the concrete.
End of explanation
room1 = system1.add_component('room1', 
                              'Component3DAcoustical', 
                              material='air',
                              length=4.0,
                              height=2.5,
                              width=5.0)
room2 = system1.add_component('room2', 
                              'Component3DAcoustical', 
                              material='air',
                              length=5.0,
                              height=2.5,
                              width=5.0)
Explanation: Rooms and wall
Now we add the two rooms.
End of explanation
room1.mass
Explanation: Given the material type and the volume we can for example calculate the mass of the air in the room
End of explanation
fig = room1.subsystem_long.plot("modal_density", yscale='log')
Explanation: or plot the modal density of the subsystem representing longitudinal waves
End of explanation
wall = system1.add_component('wall', 
                             'Component2DPlate', 
                             material='concrete', 
                             length=3.0,
                             width=2.5,
                             height=0.05)
Explanation: We now add the concrete wall.
End of explanation
system1.info(system1.subsystems, 'modal_density')
Explanation: Let's have a look at the modal densities of the subsystems.
End of explanation
wall.subsystem_bend.info(['soundspeed_group', 
                          'soundspeed_phase', 
                          'modal_density',
                          'average_frequency_spacing',
                          'power_input',
                          'dlf',
                          'tlf',])
Explanation: The modal density of the subsystem representing bending waves in the wall seems to remain constant.
It's also possible to inspect objects further. For example, as was shown with the mass of the room, it is possible to request e.g. multiple parameters.
End of explanation
junction1 = system1.add_junction('junction1', 'Junction', shape='Surface', components=['room1', 
                                                                                      'room2', 
                                                                                      'wall'])
Explanation: Shown is now a table, but what is returned is in fact a pandas DataFrame. Pandas is a data analysis toolkit and offers powerful tools to analyse data and to export data to e.g. spreadsheet formats like Excel.
Junction
The rooms and the wall form a junction and connect along a surface.
End of explanation
junction1.update_couplings()
Explanation: Now, when we call junction1.update_couplings it tries to determine all the couplings between the subsystems of the components that were added.
End of explanation
system1.info(system1.couplings, 'clf')
Explanation: We can now for example see the coupling loss factors of all the couplings that were added.
End of explanation
system1.info(system1.subsystems, 'tlf')
Explanation: Now that both the coupling loss factors and damping loss factors are known we can also list the total loss factor
End of explanation
system1.get_object('room1_SubsystemLong_room2_SubsystemLong').info(['tau', 'sound_reduction_index'])
system1.get_object('wall_SubsystemBend_room1_SubsystemLong').info(['critical_frequency'])
Explanation: The coupling loss factor of the coupling between the rooms is based on the non-resonant transmission coefficient.
End of explanation
excitation1 = room1.subsystem_long.add_excitation('excitation1', 
                                                 'ExcitationPointVolume', 
                                                 velocity=0.001,
                                                 radius=0.05)
Explanation: Excitation
We have defined the subsystems and couplings. What's left is to add an excitation to the system.
End of explanation
excitation1.info(['resistance'])
Explanation: The input power $P$ depends on the volume velocity $U$ of the source and the real part of the radiation impedance, i.e. the radiation resistance $R$.
End of explanation
fig = excitation1.plot('power_level')
Explanation: The resistance increases with frequency and therefore the radiated power increases similary.
End of explanation
system1.solve()
Explanation: Solving the system
Now we can solve the system.
End of explanation
system1.info(system1.subsystems, 'modal_energy')
Explanation: We can have a look at the modal energy
End of explanation
system1.info(['room1', 'room2'], 'pressure_level')
Explanation: but those values are generally hard to interpret. Instead, we could just request the sound pressure levels in the rooms
End of explanation
fig = system1.plot(['room1', 'room2'], 'pressure_level')
Explanation: or plot them.
End of explanation
(room1.info(['pressure_level']) - room2.info(['pressure_level']))
fig = system1.get_object('room1_SubsystemLong_room2_SubsystemLong').plot('sound_reduction_index')
Explanation: Let's consider the sound pressure level difference between the two rooms.
End of explanation
system1.info(system1.subsystems, 'modal_energy')
Explanation: Obviously, we can also look at the modal energies
End of explanation
system1.info(system1.subsystems, 'velocity_level')
system1.info(system1.subsystems, 'pressure_level')
Explanation: or see the level contributions of the individual subsystems.
End of explanation
for obj in wall.linked_subsystems:
    print(obj.name)
Explanation: Path analysis and graphs
All the objects in SeaPy remember to which other objects they're connected. For example, we can list the subsystems in a component.
End of explanation
import networkx as nx
Explanation: As soon as a model gets a bit bigger it can be hard to track which objects are connected. One way to help with keeping an overview is by drawing graphs.
End of explanation
G = system1.path_analysis.graph(['components', 'subsystems'])
nx.draw_networkx(G)
Explanation: The following graph shows the relation between components and subsystems.
End of explanation
G = system1.path_analysis.graph(['subsystems', 'couplings'])
fig = nx.draw_networkx(G)
from seapy.tools import graph_couplings
G = graph_couplings(system1)
fig = nx.draw_networkx(G)
Explanation: We can also show for example subsystems and couplings.
End of explanation
system1.path_analysis.has_path('room1_SubsystemLong', 'room2_SubsystemLong')
Explanation: Path analysis
By creating graphs of subsystems and couplings it is also straightforward to check whether subsystems are in anyway connected
End of explanation
for path in system1.path_analysis.paths('room1_SubsystemLong', 'room2_SubsystemLong'):
    print(path)
Explanation: and to determine the possible paths between any two subsystems.
End of explanation
for path in system1.path_analysis.paths('room1_SubsystemLong', 'room2_SubsystemLong'):
    print(path.level_difference)
list(system1.path_analysis.paths('room1_SubsystemLong', 'room2_SubsystemLong'))[0].level_difference
Explanation: We can also calculate the level difference due to a transmission path.
End of explanation
system1.save("model.yaml")
Explanation: Saving and restoring a model
SEA models can be saved as YAML.
End of explanation
!head -n 20 model.yaml
Explanation: YAML is a human-readable file format. Models can be implemented or edited in the YAML file if desired.
End of explanation
system2 = System.load("model.yaml")
Explanation: Loading is done using the load method.
End of explanation
system1.info(system1.subsystems, 'modal_energy')
system2.info(system2.subsystems, 'modal_energy')
Explanation: To verify whether the models are similar we check the modal energy.
End of explanation
system2.solve()
system2.info(system2.subsystems, 'modal_energy')
Explanation: That looks correctly. To be really sure we just calculate the modal energies again in the second model, to verify that other parameters have also been restored.
End of explanation
from IPython.display import IFrame
IFrame("https://seapy.readthedocs.io/en/latest/", width=800, height=600)
Explanation: Same results.
Source code and documentation
Source code of seapy can be found at GitHub and documentation right here.
End of explanation
<END_TASK>