I need to know in this below code the "class" is necessary or not, this below code is sub program, the funnction "transistor_regions, saturation_condition, performance_metrics = simulator.run_simulation(input_parameters)" is called by another main program to run the below sub program. if the class is not necessary plase remove and update the below code appropriately.

import paramiko
import time
import logging

class CircuitSimulator:
    def __init__(self, server_address, username, password):
        self.server_address = server_address
        self.username = username
        self.password = password
        self.ssh = paramiko.SSHClient()
        self.ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
        self.shell = None
    
    def connect(self):
        try:
            self.ssh.connect(self.server_address, username=self.username, password=self.password)
            self.shell = self.ssh.invoke_shell()
            while not self.shell.recv_ready():
                pass
            self.shell.send('csh\n')
            time.sleep(1)  # Add a delay to ensure shell is ready
        except Exception as e:
            print(f"Error connecting to server: {e}")
    
    def run_simulation(self, input_parameters):
        try:
            # Path configurations
            remote_text_path = '/home/userdata/xxxxx/xyz.txt'
            local_text_path = r'D:\asdf\OPAMPOTAresult.txt'

            # Generate Ocean script with updated parameter values
            ocean_script_content = self.generate_ocean_script(input_parameters)
            
            # Send Ocean script to temporary file on remote server
            with self.ssh.open_sftp().file('/home/userdata/xxxxx/temp_xyz.ocn', 'w') as temp_script_file:
                temp_script_file.write(ocean_script_content)
            
            # Run Ocean script using 'ocean' command
            ocean_command = 'ocean -nograph -replay /home/userdata/xxxxx/temp_xyz.ocn -log temp_xyz.log'
            self.shell.send(ocean_command + '\n')
            
            # Wait for command to finish and capture output
            output = ''
            while not output.endswith("$ "):  # Assuming shell prompt ends with "$ "
                output += self.shell.recv(1024).decode()            
           
            # Download the text file from the remote server
            sftp = self.ssh.open_sftp()
            sftp.get(remote_text_path, local_text_path)
            
            # Check if all transistor regions are '2'
            transistor_regions = self.check_transistor_regions(local_text_path)
            if all(region == 2 for region in transistor_regions.values()):
                saturation_condition = 'saturation'
            else:
                saturation_condition = 'not saturation'
            
            performance_metrics = self.extract_metrics(local_text_path, *input_parameters)            
           
            return transistor_regions, saturation_condition, performance_metrics
        
        except Exception as e:
            print(f"Error running simulation: {e}")
            return None, None, None, None 
    
    # Define the function to generate the Ocean script
    def generate_ocean_script(self,input_parameters):
        L1, L3, L5, L6, L7, W1, W3, W5, W6, W7, Ib, Cc = input_parameters
        print("Ocean Input_parameters", input_parameters)
        # Ocean script
        ocean_script_content = f'''
	................
            '''        
        return ocean_script_content
 
    # Function to check transistor regions
    def check_transistor_regions(self,local_text_path):
        transistor_regions = {}
        with open(local_text_path, 'r') as text_file:
            lines = text_file.readlines()
            for line in lines:
                parts = line.split()
                if len(parts) == 2:
                    transistor, region = parts[0], parts[1]
                    if transistor in ["M1", "M2", "M3", "M4", "M5", "M8", "M6", "M7"]:
                        transistor_regions[transistor] = int(region)
        return transistor_regions
    
    # Function to extract and store metrics
    def extract_metrics(self, local_text_path, L1, L3, L5, L6, L7, W1, W3, W5, W6, W7, Ib, Cc):
        performance_metrics = {}
        with open(local_text_path, 'r') as text_file:
            lines = text_file.readlines()
            for line in lines:
                parts = line.split()
                if len(parts) == 2 and parts[0] in ["Power_Dissipation", "Id5_Current", "Gain", "Bandwidth3dB", "GainBWProd", "UnityGainFreq", "PhaseMargin"]:
                    if parts[0] == "PhaseMargin":
                        phase_margin_value = self.convert_value(parts[1])
                        performance_metrics[parts[0]] = phase_margin_value + 180 if phase_margin_value < 0 else phase_margin_value
                    else:
                        performance_metrics[parts[0]] = self.convert_value(parts[1])
        default_metrics = ["Power_Dissipation", "Id5_Current", "Gain", "Bandwidth3dB", "GainBWProd", "UnityGainFreq", "PhaseMargin"]
        for metric in default_metrics:
            performance_metrics.setdefault(metric, 0.0)  
        Area = (((L1 * W1) * 2) + ((L3 * W3) * 2) + ((L5 * W5) * 2) + (L6 * W6) + (L7 * W7))
        PowerDissipation = performance_metrics.get("Power_Dissipation", 0.0) / 1e-3
        SlewRate = performance_metrics.get("Id5_Current", 0.0) / (Cc * 1e6)
        calculated_performance_metrics = {
            'Area': Area,
            'PowerDissipation': PowerDissipation,
            'SlewRate': SlewRate,
        }       
       
        # Arrange keys in the specified order
        performance_metrics = {
            'Area': calculated_performance_metrics['Area'],
            'PowerDissipation': calculated_performance_metrics.get("PowerDissipation"),
            'SlewRate': calculated_performance_metrics.get("SlewRate"),
            'Gain': performance_metrics.get("Gain", 0.0),
            'Bandwidth3dB': performance_metrics.get("Bandwidth3dB", 0.0),
            #'GainBWProd': performance_metrics.get("GainBWProd", 0.0),
            'UnityGainFreq': performance_metrics.get("UnityGainFreq", 0.0),
            'PhaseMargin': performance_metrics.get("PhaseMargin", 0.0),
        }
        print("Performance_Metrics", performance_metrics)
        return performance_metrics
    
    # Function to convert value with unit
    def convert_value(self, value):
        conversion_factors = {'k': 1e3, 'K': 1e3, 'M': 1e6, 'G': 1e9, 'T': 1e12, 'm': 1e-3, 'u': 1e-6, 'n': 1e-9, 'p': 1e-12, 'f': 1e-15,}
        for factor, multiplier in conversion_factors.items():
            if factor in value:
                return float(value.replace(factor, '')) * multiplier
        return float(value)
    
    def close(self):
        try:
            if self.shell:
                self.shell.close()
            self.ssh.close()
        except Exception as e:
            print(f"Error closing SSH connection: {e}")

# Usage:
server_address = ''
username = 'xxxxx'
password = 'yyyyy'

simulator = CircuitSimulator(server_address, username, password)
simulator.connect()
input_parameters = [0.18e-6, 0.18e-6, 0.18e-6, 0.18e-6, 0.18e-6, 1e-6, 2.52e-6, 2.16e-6, 32e-6, 13.5e-6, 15e-6, 0.44e-12, 0.8]  # Example input parameters
transistor_regions, saturation_condition, performance_metrics = simulator.run_simulation(input_parameters)
print(transistor_regions)
simulator.close()