diff --git a/deploy/api/copylot.py b/deploy/api/copylot.py index ab64fe0..d4c2163 100644 --- a/deploy/api/copylot.py +++ b/deploy/api/copylot.py @@ -1,1172 +1,1175 @@ -import sys, os -import pandas as pd -from ctypes import * -c_number = c_double #must be either c_double or c_float depending on copilot.h definition - -@CFUNCTYPE(c_int, c_number, c_char_p) -def api_callback(fprogress, msg): - """Callback function for API -> prints message from SolarPILOT DLL""" - newline = False - if fprogress != 0: - print("Progress is {:.2f} %".format(fprogress*100)) - newline = True - if msg.decode() != '': - if newline: - print("\n") - print("C++ API message -> {:s}".format(msg.decode())) - return 1 - -class CoPylot: - """ - A class to access CoPylot (SolarPILOT's Python API) - - Attributes - ---------- - pdll : class ctypes.CDLL - loaded SolarPILOT library of exported functions - - Methods - ------- - version(p_data: int) -> str - Provides SolarPILOT version number - data_create() -> int - Creates an instance of SolarPILOT in memory - data_free(p_data: int) -> bool - Frees SolarPILOT instance from memory - api_callback_create(p_data: int) -> None - Creates a callback function for message transfer - api_disable_callback(p_data: int) -> None - Disables callback function - data_set_number(p_data: int, name: str, value) -> bool - Sets a SolarPILOT numerical variable, used for float, int, bool, and numerical combo options. - data_set_string(p_data: int, name: str, svalue: str) -> bool - Sets a SolarPILOT string variable, used for string and combos - data_set_array(p_data: int, name: str, parr: list) -> bool - Sets a SolarPILOT array variable, used for double and int vectors - data_set_array_from_csv(p_data: int, name: str, fn: str) -> bool - Sets a SolarPILOT vector variable from a csv, used for double and int vectors - data_set_matrix(p_data: int, name: str, mat: list) -> bool - Sets a SolarPILOT matrix variable, used for double and int matrix - data_set_matrix_from_csv(p_data: int, name: str, fn: str) -> bool - Sets a SolarPILOT matrix variable from a csv, used for double and int matrix - data_get_number(p_data: int, name: str) -> float - Gets a SolarPILOT numerical variable value - data_get_string(p_data: int, name: str) -> str - Gets a SolarPILOT string variable value - data_get_array(p_data: int, name: str) -> list - Gets a SolarPILOT array (vector) variable value - data_get_matrix(p_data: int,name: str) -> list - Gets a SolarPILOT matrix variable value - reset_vars(p_data: int) -> bool - Resets SolarPILOT variable values to defaults - add_receiver(p_data: int, rec_name: str) -> int - Creates a receiver object - drop_receiver(p_data: int, rec_name: str) -> bool - Deletes a receiver object - add_heliostat_template(p_data: int, helio_name: str) -> int - Creates a heliostat template object - drop_heliostat_template(p_data: int, helio_name: str) -> bool - Deletes heliostat template object - update_geometry(p_data: int) -> bool - Refresh the solar field, receiver, or ambient condition settings based on current parameter settings - generate_layout(p_data: int, nthreads: int = 0) -> bool - Create a solar field layout - assign_layout(p_data: int, helio_data: list, nthreads: int = 0) -> bool - Run layout with specified positions, (optional canting and aimpoints) - get_layout_info(p_data: int, get_corners: bool = False, restype: str = "dataframe") - Get information regarding the heliostat field layout - simulate(p_data: int, nthreads: int = 1, update_aimpoints: bool = True) -> bool - Calculate heliostat field performance - summary_results(p_data: int, save_dict: bool = True) - Prints table of summary results from each simulation - detail_results(p_data: int, selhel: list = None, restype: str = "dataframe", get_corners: bool = False) - Get heliostat field layout detail results - get_fluxmap(p_data: int, rec_id: int = 0) -> list - Retrieve the receiver fluxmap, optionally specifying the receiver ID to retrive - clear_land(p_data: int, clear_type: str = None) -> None - Reset the land boundary polygons, clearing any data - add_land(p_data: int, add_type: str, poly_points: list, is_append: bool = True) -> bool - Add land inclusion or a land exclusion region within a specified polygon - heliostats_by_region(p_data: int, coor_sys: str = 'all', **kwargs) - Returns heliostats that exists within a region - modify_heliostats(p_data: int, helio_dict: dict) -> bool - Modify attributes of a subset of heliostats in the current layout - save_from_script(p_data: int, sp_fname: str) -> bool - Save the current case as a SolarPILOT .spt file - dump_varmap_tofile(p_data: int, fname: str) -> bool - Dump the variable structure to a text csv file - """ - - def __init__(self, debug: bool = False): - cwd = os.getcwd() - is_debugging = debug - if sys.platform == 'win32' or sys.platform == 'cygwin': - if is_debugging: - self.pdll = CDLL(cwd + "/solarpilotd.dll") - else: - self.pdll = CDLL(cwd + "/solarpilot.dll") - elif sys.platform == 'darwin': - self.pdll = CDLL(cwd + "/solarpilot.dylib") # Never tested - elif sys.platform.startswith('linux'): - self.pdll = CDLL(cwd +"/solarpilot.so") # Never tested - else: - print( 'Platform not supported ', sys.platform) - - def version(self, p_data: int) -> str: - """Provides SolarPILOT version number - - Parameters - ---------- - p_data : int - memory address of SolarPILOT instance - - Returns - ------- - str - SolarPILOT version number - """ - - self.pdll.sp_version.restype = c_char_p - return self.pdll.sp_version(c_void_p(p_data) ).decode() - - def data_create(self) -> int: - """Creates an instance of SolarPILOT in memory - - Returns - ------- - int - memory address of SolarPILOT instance - """ - - self.pdll.sp_data_create.restype = c_void_p - return self.pdll.sp_data_create() - - def data_free(self, p_data: int) -> bool: - """Frees SolarPILOT instance from memory - - Parameters - ---------- - p_data : int - memory address of SolarPILOT instance - - Returns - ------- - bool - True if successful, False otherwise - """ - - self.pdll.sp_data_free.restype = c_bool - return self.pdll.sp_data_free(c_void_p(p_data)) - - def api_callback_create(self,p_data: int) -> None: - """Creates a callback function for message transfer - - Parameters - ---------- - p_data : int - memory address of SolarPILOT instance - """ - - self.pdll.sp_set_callback(c_void_p(p_data), api_callback) - - def api_disable_callback(self,p_data: int) -> None: - """Disables callback function - - Parameters - ---------- - p_data : int - memory address of SolarPILOT instance - """ - - self.pdll.sp_disable_callback(c_void_p(p_data)) - - #SPEXPORT bool sp_set_number(sp_data_t p_data, const char* name, sp_number_t v); - def data_set_number(self, p_data: int, name: str, value) -> bool: - """Sets a SolarPILOT numerical variable, used for float, int, bool, and numerical combo options. - - Parameters - ---------- - p_data : int - memory address of SolarPILOT instance - name : str - SolarPILOT variable name - value: float, int, bool - Desired variable value - - Returns - ------- - bool - True if successful, False otherwise - """ - - self.pdll.sp_set_number.restype = c_bool - return self.pdll.sp_set_number(c_void_p(p_data), c_char_p(name.encode()), c_number(value)) - - #SPEXPORT bool sp_set_string(sp_data_t p_data, const char *name, const char *value) - def data_set_string(self, p_data: int, name: str, svalue: str) -> bool: - """Sets a SolarPILOT string variable, used for string and combos - - Parameters - ---------- - p_data : int - memory address of SolarPILOT instance - name : str - SolarPILOT variable name - svalue : str - Desired variable str value - - Returns - ------- - bool - True if successful, False otherwise - """ - - self.pdll.sp_set_string.restype = c_bool - return self.pdll.sp_set_string(c_void_p(p_data), c_char_p(name.encode()), c_char_p(svalue.encode())) - - #SPEXPORT bool sp_set_array(sp_data_t p_data, const char *name, sp_number_t *pvalues, int length) - def data_set_array(self, p_data: int, name: str, parr: list) -> bool: - """Sets a SolarPILOT array variable, used for double and int vectors - - Parameters - ---------- - p_data : int - memory address of SolarPILOT instance - name : str - SolarPILOT variable name - parr : list - Vector of data (float or int) \n - - Returns - ------- - bool - True if successful, False otherwise - """ - - count = len(parr) - arr = (c_number*count)() - arr[:] = parr # set all at once - self.pdll.sp_set_array.restype = c_bool - return self.pdll.sp_set_array(c_void_p(p_data), c_char_p(name.encode()), pointer(arr), c_int(count)) - - # Set array variable through a csv file - def data_set_array_from_csv(self, p_data: int, name: str, fn: str) -> bool: - """Sets a SolarPILOT vector variable from a csv, used for double and int vectors - - Parameters - ---------- - p_data : int - memory address of SolarPILOT instance - name : str - SolarPILOT variable name - fn : str - CSV file path - - Returns - ------- - bool - True if successful, False otherwise - """ - - f = open(fn, 'r', encoding="utf-8-sig") - data = [] - for line in f: - data.extend([n for n in map(float, line.split(','))]) - f.close() - return self.data_set_array(p_data, name, data) - - #SPEXPORT bool sp_set_matrix(sp_data_t p_data, const char *name, sp_number_t *pvalues, int nrows, int ncols) - def data_set_matrix(self, p_data: int, name: str, mat: list) -> bool: - """Sets a SolarPILOT matrix variable, used for double and int matrix - - Parameters - ---------- - p_data : int - memory address of SolarPILOT instance - name : str - SolarPILOT variable name - mat : list of list - Matrix of data - - Returns - ------- - bool - True if successful, False otherwise - """ - - nrows = len(mat) - ncols = len(mat[0]) - size = nrows*ncols - arr = (c_number*size)() - idx = 0 - for r in range(nrows): - for c in range(ncols): - arr[idx] = c_number(mat[r][c]) - idx += 1 - self.pdll.sp_set_matrix.restype = c_bool - return self.pdll.sp_set_matrix( c_void_p(p_data), c_char_p(name.encode()), pointer(arr), c_int(nrows), c_int(ncols)) - - # Set matrix variable values through a csv file - def data_set_matrix_from_csv(self, p_data: int, name: str, fn: str) -> bool: - """Sets a SolarPILOT matrix variable from a csv, used for double and int matrix - - Parameters - ---------- - p_data : int - memory address of SolarPILOT instance - name : str - SolarPILOT variable name - fn : str - CSV file path - - Returns - ------- - bool - True if successful, False otherwise - """ - - f = open(fn, 'r', encoding="utf-8-sig") - data = [] - for line in f : - lst = ([n for n in map(float, line.split(','))]) - data.append(lst) - f.close() - return self.data_set_matrix(p_data, name, data) - - #SPEXPORT sp_number_t sp_get_number(sp_data_t p_data, const char* name) - def data_get_number(self, p_data: int, name: str) -> float: - """Gets a SolarPILOT numerical variable value - - Parameters - ---------- - p_data : int - memory address of SolarPILOT instance - name : str - SolarPILOT variable name - - Returns - ------- - float - Variable value - """ - - self.pdll.sp_get_number.restype = c_number - return self.pdll.sp_get_number(c_void_p(p_data), c_char_p(name.encode())) - - #SPEXPORT const char *sp_get_string(sp_data_t p_data, const char *name) - def data_get_string(self, p_data: int, name: str) -> str: - """Gets a SolarPILOT string variable value - - Parameters - ---------- - p_data : int - memory address of SolarPILOT instance - name : str - SolarPILOT variable name - - Returns - ------- - str - Variable value - """ - - self.pdll.sp_get_string.restype = c_char_p - return self.pdll.sp_get_string(c_void_p(p_data), c_char_p(name.encode())).decode() - - #SPEXPORT sp_number_t *sp_get_array(sp_data_t p_data, const char *name, int *length) - def data_get_array(self, p_data: int, name: str) -> list: - """Gets a SolarPILOT array (vector) variable value - - Parameters - ---------- - p_data : int - memory address of SolarPILOT instance - name : str - SolarPILOT variable name - - Returns - ------- - list - Variable value - """ - - count = c_int() - self.pdll.sp_get_array.restype = POINTER(c_number) - parr = self.pdll.sp_get_array(c_void_p(p_data), c_char_p(name.encode()), byref(count)) - arr = parr[0:count.value] - return arr - - #SPEXPORT sp_number_t *sp_get_matrix(sp_data_t p_data, const char *name, int *nrows, int *ncols) - def data_get_matrix(self,p_data: int,name: str) -> list: - """Gets a SolarPILOT matrix variable value - - Parameters - ---------- - p_data : int - memory address of SolarPILOT instance - name : str - SolarPILOT variable name - - Returns - ------- - list of list - Variable value - """ - - nrows = c_int() - ncols = c_int() - self.pdll.sp_get_matrix.restype = POINTER(c_number) - parr = self.pdll.sp_get_matrix( c_void_p(p_data), c_char_p(name.encode()), byref(nrows), byref(ncols) ) - mat = [] - for r in range(nrows.value): - row = [] - for c in range(ncols.value): - row.append( float(parr[ncols.value * r + c])) - mat.append(row) - return mat - - #SPEXPORT void sp_reset_geometry(sp_data_t p_data) - def reset_vars(self, p_data: int) -> bool: - """Resets SolarPILOT variable values to defaults - - Parameters - ---------- - p_data : int - memory address of SolarPILOT instance - - Returns - ------- - bool - True if successful, False otherwise - """ - - return self.pdll.sp_reset_geometry( c_void_p(p_data)) - - #SPEXPORT int sp_add_receiver(sp_data_t p_data, const char* receiver_name) - def add_receiver(self, p_data: int, rec_name: str) -> int: - """Creates a receiver object - - NOTE: CoPylot starts with a default receiver configuration at receiver object ID = 0, with 'Receiver 1' as the receiver's name. - If you add a receiver object without dropping this default receiver, generating a layout will result in a multi-receiver problem, - which could produce strange results. - - Parameters - ---------- - p_data : int - memory address of SolarPILOT instance - rec_name : str - Receiver name - - Returns - ------- - int - Receiver object ID - """ - - self.pdll.sp_add_receiver.restype = c_int - return self.pdll.sp_add_receiver( c_void_p(p_data), c_char_p(rec_name.encode())) - - #SPEXPORT bool sp_drop_receiver(sp_data_t p_data, const char* receiver_name) - def drop_receiver(self, p_data: int, rec_name: str) -> bool: - """Deletes a receiver object - - Parameters - ---------- - p_data : int - memory address of SolarPILOT instance - rec_name : str - Receiver name - - Returns - ------- - bool - True if successful, False otherwise - """ - - self.pdll.sp_drop_receiver.restype = c_bool - return self.pdll.sp_drop_receiver( c_void_p(p_data), c_char_p(rec_name.encode())) - - #SPEXPORT int sp_add_heliostat_template(sp_data_t p_data, const char* heliostat_name) - def add_heliostat_template(self, p_data: int, helio_name: str) -> int: - """Creates a heliostat template object - - NOTE: CoPylot starts with a default heliostat template at ID = 0, with 'Template 1' as the Heliostat's name. - If you add a heliostat template object without dropping this default template, generating a layout will fail - because the default heliostat geometry distribution ('solarfield.0.template_rule') is 'Use single template' - but the select heliostat geometry ('solarfield.0.temp_which') is not defined. - - Parameters - ---------- - p_data : int - memory address of SolarPILOT instance - helio_name : str - heliostat template name - - Returns - ------- - int - heliostate template ID - """ - - self.pdll.sp_add_heliostat_template.restype = c_int - return self.pdll.sp_add_heliostat_template( c_void_p(p_data), c_char_p(helio_name.encode())) - - #SPEXPORT bool sp_drop_heliostat_template(sp_data_t p_data, const char* heliostat_name) - def drop_heliostat_template(self, p_data: int, helio_name: str) -> bool: - """Deletes heliostat template object - - Parameters - ---------- - p_data : int - memory address of SolarPILOT instance - helio_name : str - Heliostat template name - - Returns - ------- - bool - True if successful, False otherwise - """ - - self.pdll.sp_drop_heliostat_template.restype = c_bool - return self.pdll.sp_drop_heliostat_template( c_void_p(p_data), c_char_p(helio_name.encode())) - - #SPEXPORT bool sp_update_geometry(sp_data_t p_data) - def update_geometry(self, p_data: int) -> bool: - """Refresh the solar field, receiver, or ambient condition settings based on current parameter settings - - Parameters - ---------- - p_data : int - memory address of SolarPILOT instance - - Returns - ------- - bool - True if successful, False otherwise - """ - - self.pdll.sp_update_geometry.restype = c_bool - return self.pdll.sp_update_geometry( c_void_p(p_data)) - - #SPEXPORT bool sp_generate_layout(sp_data_t p_data, int nthreads = 0) - def generate_layout(self, p_data: int, nthreads: int = 0) -> bool: - """Create a solar field layout - - Parameters - ---------- - p_data : int - memory address of SolarPILOT instance - nthreads : int, optional - Number of threads to use for simulation - - Returns - ------- - bool - True if successful, False otherwise - """ - - self.pdll.sp_generate_layout.restype = c_bool - return self.pdll.sp_generate_layout( c_void_p(p_data), c_int(nthreads)) - - #SPEXPORT bool sp_assign_layout(sp_data_t p_data, sp_number_t* pvalues, int nrows, int ncols, int nthreads = 0) //, bool save_detail = true) - def assign_layout(self, p_data: int, helio_data: list, nthreads: int = 0) -> bool: - """Run layout with specified positions, (optional canting and aimpoints) - - Parameters - ---------- - p_data : int - memory address of SolarPILOT instance - helio_data : list of lists - heliostat data to assign - [