Esempio n. 1
0
def test_WP2input_tidal_init(tidalsite, tidal, tidal_kwargs):

    site = WP2_SiteData(*tidalsite)
    machine = WP2_MachineData(*tidal, **tidal_kwargs)

    WP2input(machine, site)

    assert True
Esempio n. 2
0
def test_WP2input_wavebiggamma_init(wavesitebiggamma, wave, wave_data_folder):

    site = WP2_SiteData(*wavesitebiggamma)
    machine = WP2_MachineData(*wave, wave_data_folder=wave_data_folder)

    WP2input(machine, site)

    assert True
def test_WP2_init_wave(wavesite, wave, wave_data_folder):

    site = WP2_SiteData(*wavesite)
    machine = WP2_MachineData(*wave, wave_data_folder=wave_data_folder)

    test = WP2input(machine, site)
    WP2(test)

    assert True
def test_WP2_optimisationLoop_tidal(tidalsite, tidal, tidal_kwargs):

    site = WP2_SiteData(*tidalsite)
    machine = WP2_MachineData(*tidal, **tidal_kwargs)

    data = WP2input(machine, site)
    test = WP2(data)
    result = test.optimisationLoop()

    assert result
def test_WP2_optimisationLoop_wave(wavesite, wave, wave_data_folder):

    site = WP2_SiteData(*wavesite)
    machine = WP2_MachineData(*wave, wave_data_folder=wave_data_folder)

    data = WP2input(machine, site)
    test = WP2(data)
    result = test.optimisationLoop()

    assert result
Esempio n. 6
0
#The input folder defined the place were the software will search for 
#the user tidal database or the WAMIT folder or the WP2Input.wp2 file or the iWP2Pickler.pkl file
#InputFolder = 'C:\\Users\\fferri\\Desktop\\dtocean_tidal'
#DATAfolder = (InternalModel_flag,InputFolder)

UserOutputTable = None

Machine = WP2_MachineData(Type,
                          lCS,
                          Clen,
                          YawAngle,
                          Float_flag,
                          InstalDepth,
                          MinDist,
                          OpThreshold,
                          UserArray,
                          RatedPowerArray,
                          RatedPowerDevice,
                          UserOutputTable,
			  "",
			  tidal_power_curve=Cp,
                          tidal_thrust_curve=Ct,
                          tidal_bidirectional=Bidirection,
                          tidal_cutinout=C_IO,
                          tidal_velocity_curve=X)

" Input assembly "
iWP2input = WP2input(Machine,Site)

if not iWP2input.stopWP2run:
    WPobj = WP2(iWP2input,debug=False)
    #Out = WPobj.optimisationLoop(FixedLayOut=FixedArrayLayout)
UserArray = {'Option': 1, 'Value': 'rectangular'}

RatedPowerArray = 20
RatedPowerDevice = 1

#This will trigger the WAMIT or Nemoh calculation for the wave case
#and it is used in the tidal case for check on the user database format
#compability
InternalModel_flag = True

#The input folder defined the place were the software will search for
#the user tidal database or the WAMIT folder or the WP2Input.wp2 file or the iWP2Pickler.pkl file
InputFolder = ''
DATAfolder = (InternalModel_flag, InputFolder)

UserOutputTable = None

Machine = WP2_MachineData(Type, lCS, Clen, YawAngle, SingleMachine, Float_flag,
                          InstalDepth, MinDist, OpThreshold, DATAfolder,
                          UserArray, RatedPowerArray, RatedPowerDevice,
                          UserOutputTable)

" Input assembly "
iWP2input = WP2input(Machine, Site)

if not iWP2input.stopWP2run:
    WPobj = WP2(iWP2input, debug=True)
    #Out = WPobj.optimisationLoop(FixedLayOut=FixedArrayLayout)
    Out = WPobj.optimisationLoop()
    Out.printRes()
Esempio n. 8
0
    def connect(self, debug_entry=False, export_data=True):
        '''The connect method is used to execute the external program and 
        populate the interface data store with values.
        
        Note:
          Collecting data from the interface for use in the external program
          can be accessed using self.data.my_input_variable. To put new values
          into the interface once the program has run we set
          self.data.my_output_variable = value
        
        '''

        #   #------------------------------------------------------------------------------
        #   #------------------------------------------------------------------------------
        #   #------------------ WP2 site data class
        #   #------------------------------------------------------------------------------
        #   #------------------------------------------------------------------------------
        #   Sitedata class: The class contains all the information relative to the area of deployment
        #	 of the array.
        #
        #	 Args:
        #	    LeaseArea (numpy.ndarray) [m]: UTM coordinates of the lease area poligon expressed as [X,Y].
        #		                           X is the column vector containing the easting coordinates
        #		                           Y is the column vector containing the northing coordinates
        #		NogoAreas (list) [m]: list containing the UTM coordinates of the nogo areas poligons expressed as [X,Y].
        #		MeteoceanConditions (dict): dictionary gathering all the information related to the metocean conditions
        #		                            of the site. The dictionary is different for wave and tidal cases:
        #									Wave keys:
        #									   'Te' (numpy.ndarray)[s]: Vector containing the wave energy periods
        #										'Hs' (numpy.ndarray)[m]: Vector containing the significant wave height
        #										'dir' (numpy.ndarray)[rad]: Vector containing the wave direction
        #										'p' (numpy.ndarray)[-]: Probability of occurence of the sea state
        #										'specType' (tup): description of the spectral shape recorded at the site
        #																	(spectrum name, gamma factor, spreading parameter)
        #										'SSH' (float)[m]: Sea Surface Height wrt the bathymetry datum at a single point
        #									Tidal keys:
        #									   'V' (numpy.ndarray)[m/s]: northing-direction of the velocity field
        #										'U' (numpy.ndarray)[m/s]: easting-direction of the velocity field
        #										'p' (numpy.ndarray)[-]: probability of occurency of the state
        #										'TI' (numpy.ndarray)[-]: Turbulence intensity. It can be a single float or a matrix where the
        #											      TI is specified at each grid node.
        #										'x' (numpy.ndarray)[m]: Vector containing the easting coordinate of the grid nodes
        #										'y' (numpy.ndarray)[m]: Vector containing the northing coordinate of the grid nodes
        #										'SSH' (numpy.ndarray)[m]: Sea Surface Height wrt the bathymetry datum
        #
        #
        #		VelocityShear (numpy.ndarray) [-]: Tidal velocity shear formula (power law), used to evaluate the vertical velocity profile
        #		Main_Direction (numpy.ndarray, optional) [m]: xy vector defining the main orientation of the array. If not provided it will be
        #														assessed from the Metocean conditions.
        #		Bathymetry (numpy.ndarray) [m]: Describes the vertical profile of the sea bottom at each (given) UTM coordinate.
        #										Expressed as [X,Y,Z]
        #		Geophysics (numpy.ndarray) [?]: Describes the sea bottom geophysic characteristic at each (given) UTM coordinate.
        #										Expressed as [X,Y,Geo]
        #		BR (float) [-]: describes the ratio between the lease area surface over the site area surface enclosed in a channel.
        #						1. - closed channel
        #						0. - open sea
        #		electrical_connection_point (numpy.ndarray) [m]: UTM coordinates of the electrical connection point at the shore line
        #        boundary_padding (float, optional) [m]: Padding added to inside of the lease area in which devices may not be placed

        # Check whether the bin width divides the RP perfectly
        check_bin_widths(self.data.rated_power_device, self.data.pow_bins)

        if 'Tidal' in self.data.type:

            x = self.data.tidal_series.coords["UTM x"]
            y = self.data.tidal_series.coords["UTM y"]

            tide_dict = {
                "U": self.data.tidal_series.U.values,
                "V": self.data.tidal_series.V.values,
                "SSH": self.data.tidal_series.SSH.values,
                "TI": self.data.tidal_series.TI.values,
                "x": x.values,
                "y": y.values,
                "t": self.data.tidal_series.t.values,
                "xc": self.data.tidal_occurrence_point.x,
                "yc": self.data.tidal_occurrence_point.y,
                "ns": self.data.tidal_nbins
            }

            occurrence_matrix = make_tide_statistics(tide_dict)

            p_total = sum(occurrence_matrix['p'])

            if not np.isclose(p_total, 1.):

                errStr = ("Tidal statistics probabilities invalid. Total "
                          "probability equals {}").format(p_total)
                raise ValueError(errStr)

            occurrence_matrix_coords = [
                occurrence_matrix['x'], occurrence_matrix['y'],
                occurrence_matrix['p']
            ]

            matrix_xset = {
                "values": {
                    "U": occurrence_matrix['U'],
                    "V": occurrence_matrix['V'],
                    "SSH": occurrence_matrix['SSH'],
                    "TI": occurrence_matrix['TI']
                },
                "coords": occurrence_matrix_coords
            }

            self.data.tidal_occurrence = matrix_xset

            x = self.data.geophysics.coords["UTM x"]
            y = self.data.geophysics.coords["UTM y"]

            # Flatten mannings number
            xgrid, ygrid = np.meshgrid(x.values, y.values)
            geogrid = self.data.geophysics.values.T
            geoflat = np.array(
                zip(xgrid.flatten(), ygrid.flatten(), geogrid.flatten()))

        else:

            occurrence_matrix = make_wave_statistics(self.data.wave_series)

            p_total = occurrence_matrix['p'].sum()

            if not np.isclose(p_total, 1.):

                errStr = ("Wave statistics probabilities invalid. Total "
                          "probability equals {}").format(p_total)
                raise ValueError(errStr)

            occurrence_matrix_coords = [
                occurrence_matrix['Te'], occurrence_matrix['Hs'],
                occurrence_matrix['B']
            ]
            matrix_xgrid = {
                "values": occurrence_matrix['p'],
                "coords": occurrence_matrix_coords
            }

            self.data.wave_occurrence = matrix_xgrid

            # Translate spectrum type
            spectrum_map = {
                "Regular": "Regular",
                "Pierson-Moskowitz": "Pierson_Moskowitz",
                "JONSWAP": "Jonswap",
                "Bretschneider": "Bretschneider_Mitsuyasu",
                "Modified Bretschneider": "Modified_Bretschneider_Mitsuyasu"
            }

            spectrum_type = spectrum_map[self.data.spectrum_type_farm]

            spectrum_list = (spectrum_type, self.data.spectrum_gamma_farm,
                             self.data.spectrum_dir_spreading_farm)

            occurrence_matrix["SSH"] = 0.  # Datum is mean sea level
            occurrence_matrix["specType"] = spectrum_list

            geoflat = None

        # Snap lease area to bathymetry
        bathy_x = self.data.bathymetry["x"]
        bathy_y = self.data.bathymetry["y"]
        bathy_box = box(bathy_x.min(), bathy_y.min(), bathy_x.max(),
                        bathy_y.max())

        lease_area = self.data.lease_area
        sane_lease_area = lease_area.intersection(bathy_box)

        # Convert lease and nogo polygons
        numpy_lease = np.array(sane_lease_area.exterior.coords[:-1])

        if self.data.nogo_areas is None:
            numpy_nogo = None
        else:
            numpy_nogo = [
                np.array(x.exterior.coords[:-1])
                for x in self.data.nogo_areas.values()
            ]

        numpy_landing = np.array(self.data.export_landing_point.coords[0])

        # Bathymetry (**assume layer 1 in uppermost**)
        zv = self.data.bathymetry["depth"].sel(layer="layer 1").values.T
        xv, yv = np.meshgrid(self.data.bathymetry["x"].values,
                             self.data.bathymetry["y"].values)
        xyz = np.dstack([xv.flatten(), yv.flatten(), zv.flatten()])[0]
        safe_xyz = xyz[~np.isnan(xyz).any(axis=1)]

        # Convert main direction to vector
        if self.data.main_direction is None:
            main_direction_vec = None
        else:
            main_direction_tuple = bearing_to_vector(self.data.main_direction)
            main_direction_vec = np.array(main_direction_tuple)

        Site = WP2_SiteData(numpy_lease, numpy_nogo, occurrence_matrix, 7.,
                            main_direction_vec, safe_xyz, geoflat,
                            self.data.blockage_ratio, numpy_landing,
                            self.data.boundary_padding)

        #	#------------------------------------------------------------------------------
        #	#------------------------------------------------------------------------------
        #	#------------------ WP2 machine data class
        #	#------------------------------------------------------------------------------
        #	#------------------------------------------------------------------------------
        #
        #    MachineData class: The class contains all the information relative to the machine
        #	deployed in the array.
        #
        #	Args:
        #		Type (str)[-]: defines the type of device either 'tidal' or 'wave'. No other strings are accepted
        #		lCS (numpy.ndarray)[m]: position vector of the local coordina system from the given reference point.
        #								Wave: represents the position vector of the body CS wrt the mesh CS
        #								Tidal: represents the position of the hub from the machine (reference) CS.
        #		Clen (numpy.ndarray)[m]: characteristic lenght of the device:
        #						 Wave: unused
        #						 Tidal: turbine diameter and distance of the hub from the center line
        #						        used in case the machine is composed by two parallel turbines
        #		YawAngle (float)[rad]: Yaw angle span, wrt the main direction of the array.
        #							The total yawing range is two-fold the span. -Yaw/+Yaw
        #		Float_flag (bool)[-]: defines whether the machine is floating (True) or not (False)
        #		InstalDepth (list)[m]: defines the min and maximum water depth at which the device can be installed
        #		MinDist (tuple)[m]: defines the minimum allowed distance between devices in the array configuration
        #		                    the first element is the distance in the x axis
        #		                    the second element is the distance in the y axis
        #		OpThreshold (float)[-]: defines the minimum allowed q-facto
        #		UserArray (dict): dictionary containing the description of the array layout to be optimise. Keys:
        #						'Option' (int): 1-optimisation over the internal parametric array layouts
        #										2-fixed array layout specified by the user not subject to optimisation
        #										3-array layout specified by the user subject to optimisation via expantion of the array
        #						'Value' options:
        #								(str) 'rectangular'
        #								(str) 'staggered'
        #								(str) 'full'
        #								(numpy.ndarray) [m]: [X,Y] coordiantes of the device
        #        RatedPowerArray (float)[W]: Rated power of the array.
        #        RatedPowerDevice (float)[W]: Rated power of the single isolated device.
        #        UserOutputTable (dict, optional): dictionary of dictionaries where all the array layouts inputed and analysed by the user are
        #								  collected. Using this option the internal WP2 calculation is skipped, and the optimisaton
        #								  is performed in the given data. The dictionaies keys are the arguments of the WP2 Output class.
        #        wave_data_folder (string, optional): path name of the hydrodynamic results generate by the wave external module
        #        tidal_power_curve (numpy.ndarray, optional)[-]: Power curve function of the stream velocity
        #        tidal_thrust_curve (numpy.ndarray, optional)[-]: Thrust curve function of the stream velocity
        #        tidal_velocity_curve (numpy.ndarray, optional)[m/s]: Vector containing the stream velocity
        #        tidal_cutinout (numpy.ndarray, optional): contain the cut_in and cut_out velocity of the turbine.
        #								                        Outside the cut IN/OUT velocity range the machine will not produce
        #								                        power. The generator is shut down, but the machine will still interact
        #								                        with the others.
        #        tidal_bidirectional (bool, optional): bidirectional working principle of the turbine
        #        tidal_data_folder (string, optional): Path to tidal device CFD data files

        yaw_angle = np.radians(self.data.yaw_angle)
        min_install = self.data.min_install
        max_install = self.data.max_install
        min_dist = (self.data.min_dist_x, self.data.min_dist_y)
        op_threshold = self.data.op_threshold
        install_depth = (min_install, max_install)

        if 'Tidal' in self.data.type:

            perf_velocity = self.data.perf_curves.index.values
            cp_curve = self.data.perf_curves["Coefficient of Power"].values
            ct_curve = self.data.perf_curves["Coefficient of Thrust"].values
            cut_in = self.data.cut_in
            cut_out = self.data.cut_out

            dev_type = "Tidal"
            lCS = [0, 0, self.data.hub_height]
            clen = (self.data.rotor_diam, self.data.turbine_interdist)
            wave_data_folder = None
            tidal_power_curve = cp_curve
            tidal_thrust_curve = ct_curve
            tidal_velocity_curve = perf_velocity
            tidal_cutinout = (cut_in, cut_out)
            tidal_bidirectional = self.data.bidirection
            tidal_data_folder = self.data.tidal_data_directory

        else:

            dev_type = "Wave"
            lCS = None
            clen = None
            wave_data_folder = self.data.wave_data_directory
            tidal_power_curve = None
            tidal_thrust_curve = None
            tidal_velocity_curve = None
            tidal_cutinout = None
            tidal_bidirectional = None
            tidal_data_folder = None

        # Set user_array_dict value key
        if self.data.user_array_option in [
                "User Defined Flexible", "User Defined Fixed"
        ]:

            if self.data.user_array_layout is None:

                errStr = ("A predefined array layout must be provided when "
                          "using the '{}' array layout option").format(
                              self.data.user_array_option)
                raise ValueError(errStr)

            numpy_layout = np.array(
                [point.coords[0][:2] for point in self.data.user_array_layout])

            user_array_dict = {'Value': numpy_layout}

        else:

            user_array_dict = {'Value': self.data.user_array_option.lower()}

        # Set user_array_dict option key
        if self.data.user_array_option == "User Defined Flexible":
            user_array_dict['Option'] = 3
        elif self.data.user_array_option == "User Defined Fixed":
            user_array_dict['Option'] = 2
        else:
            user_array_dict['Option'] = 1

        if 'Floating' in self.data.type:
            float_flag = True
        else:
            float_flag = False

        Machine = WP2_MachineData(
            dev_type,
            lCS,
            clen,
            yaw_angle,
            float_flag,
            install_depth,
            min_dist,
            op_threshold,
            user_array_dict,
            self.data.rated_array_power * 1e6,  # Watts
            self.data.rated_power_device * 1e6,  # Watts
            None,
            wave_data_folder,
            tidal_power_curve,
            tidal_thrust_curve,
            tidal_velocity_curve,
            tidal_cutinout,
            tidal_bidirectional,
            tidal_data_folder)

        iWP2input = WP2input(Machine, Site)

        if export_data:

            userdir = UserDataDirectory("dtocean_core", "DTOcean", "config")

            if userdir.isfile("files.ini"):
                configdir = userdir
            else:
                configdir = ObjDirectory("dtocean_core", "config")

            files_ini = ReadINI(configdir, "files.ini")
            files_config = files_ini.get_config()

            appdir_path = userdir.get_path("..")
            debug_folder = files_config["debug"]["path"]
            debug_path = os.path.join(appdir_path, debug_folder)
            debugdir = Directory(debug_path)
            debugdir.makedir()

            pkl_path = debugdir.get_path("hydrodynamics_inputs.pkl")
            pickle.dump(iWP2input, open(pkl_path, "wb"))

        if debug_entry: return

        if not iWP2input.stopWP2run:
            main = WP2(iWP2input, pickup=True, debug=False)

            result = main.optimisationLoop()

            if result == -1:
                errStr = "Hydrodynamics module failed to execute successfully."
                raise RuntimeError(errStr)

        if export_data:

            pkl_path = debugdir.get_path("hydrodynamics_outputs.pkl")
            pickle.dump(result, open(pkl_path, "wb"))

        AEP_per_device = {}
        pow_per_device = {}
        pmf_per_device = {}
        layout = {}
        q_factor_per_device = {}
        dev_ids = []

        # Layout
        for dev_id, coords in result.Array_layout.iteritems():
            dev_id = dev_id.lower()
            layout[dev_id] = np.array(coords)
            dev_ids.append(dev_id)

        self.data.device_position = layout
        self.data.n_bodies = int(result.Nbodies)

        # Total annual energy (convert to MWh)
        self.data.AEP_array = \
                       float(result.Annual_Energy_Production_Array) / 1e6

        # Array capacity factor
        ideal_energy = (365 * 24 * self.data.n_bodies *
                        self.data.rated_power_device)
        self.data.array_efficiency = self.data.AEP_array / ideal_energy

        # Annual energy per device (convert to MWh)
        for dev_id, AEP in zip(dev_ids, result.Annual_Energy_Production_perD):
            AEP_per_device[dev_id] = float(AEP) / 1e6  #SimpleDIct

        self.data.AEP_per_device = AEP_per_device

        # Mean power per device (convert to MW)
        for dev_id, power in zip(dev_ids, result.power_prod_perD):
            pow_per_device[dev_id] = float(power) / 1e6  #SimpleDIct

        self.data.pow_per_device = pow_per_device

        for dev_id, pow_per_state in zip(dev_ids, result.power_prod_perD_perS):

            # Power probability mass function (convert to MW)
            flat_prob = occurrence_matrix['p'].flatten("F")
            pow_list = pow_per_state / 1e6

            assert np.isclose(flat_prob.sum(), 1.)
            assert len(flat_prob) == len(pow_list)

            # Find uniques powers
            unique_powers = []

            for power in pow_list:

                if not np.isclose(power, unique_powers).any():
                    unique_powers.append(power)

            # Catch any matching powers and sum the probabilities
            powers = []
            probs = []

            match_index_check = []

            for power in unique_powers:

                matches = np.isclose(power, pow_list)
                assert len(matches) >= 1
                match_idx = np.where(matches == True)
                match_probs = flat_prob[match_idx]
                match_index_check.extend(match_idx[0].tolist())

                powers.append(power)
                probs.append(match_probs.sum())

                # Nullify the found indexes to ensure uniqueness
                pow_list[match_idx] = np.nan
                flat_prob[match_idx] = np.nan

            repeated_indexes = set([
                x for x in match_index_check if match_index_check.count(x) > 1
            ])

            assert len(repeated_indexes) == 0
            assert np.isclose(sum(probs), 1.)

            pmf_per_device[dev_id] = np.array(zip(powers, probs))

        # Power probability histograms
        dev_pow_hists = make_power_histograms(pmf_per_device,
                                              self.data.rated_power_device,
                                              self.data.pow_bins)

        self.data.pow_pmf_per_device = pmf_per_device
        self.data.pow_hist_per_device = dev_pow_hists

        # Resource modification
        self.data.q_factor_per_device = q_factor_per_device
        self.data.q_factor_array = result.q_factor_Array

        self.data.resource_reduction = float(result.Resource_Reduction)

        for dev_id, q_factor in zip(dev_ids, result.q_factor_Per_Device):
            q_factor_per_device[dev_id] = q_factor

        # Main Direction
        self.data.main_direction = vector_to_bearing(*result.main_direction)

        # Device type specific outputs
        if 'Wave' in self.data.type:

            # External forces
            fex_dict = result.Hydrodynamic_Parameters
            modes = np.array(fex_dict["mode_def"])
            freqs = np.array(fex_dict["wave_fr"])

            # Convert directions to bearings
            bearings = [radians_to_bearing(x) for x in fex_dict["wave_dir"]]
            dirs = np.array(bearings)

            fex_raw = np.zeros(
                [len(modes), len(freqs), len(dirs)], dtype=complex) * np.nan

            for i, mode_fex in enumerate(fex_dict["fex"]):
                if mode_fex:
                    fex_raw[i, :, :] = np.expand_dims(mode_fex, axis=1)

            fex_xgrid = {"values": fex_raw, "coords": [modes, freqs, dirs]}

            self.data.ext_forces = fex_xgrid

            ## Power Matrix in kW
            power_matrix = result.power_matrix_machine / 1000.
            power_matrix_dims = result.power_matrix_dims

            # Convert directions to bearings
            bearings = [
                radians_to_bearing(x) for x in power_matrix_dims["dirs"]
            ]

            occurrence_matrix_coords = [
                power_matrix_dims['te'], power_matrix_dims['hm0'], bearings
            ]

            matrix_xgrid = {
                "values": power_matrix,
                "coords": occurrence_matrix_coords
            }

            self.data.power_matrix = matrix_xgrid

        return
#UserArray = {'Option':1,'Value':'full'}
UserArray = {'Option':2,'Value':FixedArrayLayout}
#UserArray = {'Option':3,'Value':np.random.rand(20,2)*200}

RatedPowerArray = 12
RatedPowerDevice = 6

UserOutputTable = None


Machine = WP2_MachineData(Type,
                          lCS,
                          Clen,
                          YawAngle,
                          Float_flag,
                          InstalDepth,
                          MinDist,
                          OpThreshold,
                          UserArray,
                          RatedPowerArray,
                          RatedPowerDevice,
                          wave_data_folder=InputFolder)


" Input assembly "
#Site.printInput(indent=1)
#help(Site)

iWP2input = WP2input(Machine,Site)

if not iWP2input.stopWP2run:
    WPobj = WP2(iWP2input,
Esempio n. 10
0
def test_WP2_MachineData_init(tidal):

    WP2_MachineData(*tidal)

    assert True
z = np.empty((1))
c_io = np.array([cut_in, cut_out])

single_machine_description = {
    'pf': Cp_curve,
    'Lf2': bidirection,
    'Lf1': Ct_curve,
    'x': performance_velocity,
    'y': y,
    'z': z,
    'Add': c_io
}

Machine = WP2_MachineData('tidal', lCS, (rotor_diam, turbine_interdist),
                          yaw_angle, single_machine_description, float_flag,
                          (min_install, max_install), (min_dist_x, min_dist_y),
                          op_threshold, {
                              'Option': 1,
                              'Value': user_array_option
                          }, rated_array_power, rated_power_device,
                          user_array_layout)

" Input assembly "
iWP2input = WP2input(Machine, Site)

if not iWP2input.stopWP2run:
    WPobj = WP2(iWP2input, debug=True)
    #Out = WPobj.optimisationLoop(FixedLayOut=FixedArrayLayout)
    Out = WPobj.optimisationLoop()
    Out.printRes()