From 6f22c2000cac7bb76e7530be0397ea09351476bb Mon Sep 17 00:00:00 2001 From: Alberto de la Calle <95384970+adlcalle@users.noreply.github.com> Date: Mon, 16 May 2022 11:21:54 -0700 Subject: [PATCH 1/2] Matlab examples Using CoPylot throught the Matlab API for Python --- deploy/api/field_eff_table.m | 82 +++++++ deploy/api/min_example.m | 49 +++++ deploy/api/test_script.m | 407 +++++++++++++++++++++++++++++++++++ 3 files changed, 538 insertions(+) create mode 100644 deploy/api/field_eff_table.m create mode 100644 deploy/api/min_example.m create mode 100644 deploy/api/test_script.m diff --git a/deploy/api/field_eff_table.m b/deploy/api/field_eff_table.m new file mode 100644 index 0000000..0d4a07c --- /dev/null +++ b/deploy/api/field_eff_table.m @@ -0,0 +1,82 @@ +% If current folder is .\source\solarpilot_dev\solarpilot\deploy\api then +% the only path needed is the location of the TMY and can be local. +TMY_file="..\climate_files\USA CA Daggett (TMY2).csv"; +cp = py.copylot.CoPylot(); + +% If current folder is any other folder then you have to provide the path +% where copylot.py and solarpilot.dll are placed, and the TMY needs the full path. +% Uncomment the following lines in that case. +% CoPylot_path='C:\Users\adelacal\source\solarpilot_dev\solarpilot\deploy\api'; +% TMY_file="C:\Users\adelacal\source\solarpilot_dev\solarpilot\deploy\climate_files\USA CA Daggett (TMY2).csv"; +% +% if count(py.sys.path,CoPylot_path) == 0 +% insert(py.sys.path,int32(0),CoPylot_path); +% end +% cp = py.copylot.CoPylot(path=CoPylot_path); + +r = cp.data_create(); +cp.data_set_string(r, "ambient.0.weather_file", TMY_file); +cp.generate_layout(r); +field = cp.get_layout_info(r); +cp.simulate(r); +flux = cp.get_fluxmap(r); + +tic +cp.calculate_optical_efficiency_table(r, py.int(12), py.int(11)); +%cp.calculate_optical_efficiency_table(r, py.int(2), py.int(2)) %# For debugging +toc + +eff_filename = "./efficiency_table.csv"; +cp.save_optical_efficiency_table(r, eff_filename), %# Testing simple table saving (consistent with get_optical_efficiency_table) +cp.save_optical_efficiency_table(r, "./modelica_efficiency_table.txt", "sf_eff_table"); %# Testing Modelica specific table output + +sf_eff = cp.get_optical_efficiency_table(r); +cp.data_free(r); + +% Read in efficiency table +eff_table=readtable(eff_filename); +ele= eff_table{1,2:end}; +azi= eff_table{2:end,1}; +eff_data = eff_table{2:end,2:end}; + +% Check data is consistent between two methods +t1(1)=isequal(azi',round(double(sf_eff.get('azimuth')),4)); +t1(2)=isequal(ele,round(double(sf_eff.get('elevation')),4)); +t1(3)=isequal(eff_data,round(double(py.numpy.array(sf_eff.get('eff_data'))),6)); + +FontSize=14; +LineWidth=1.5; +figure() +legInfoAzi=cell(length(azi),1); +hold on +for i=1:length(azi) + plot(ele,eff_data(i,:),'LineWidth',LineWidth); + legInfoAzi{i}=num2str(azi(i)); +end +hold off +xlabel('Elevation Angle [deg]') +ylabel('Solarfield Efficiency [-]') +set(gca,'FontSize',FontSize) +leg=legend(legInfoAzi,'NumColumns',2,'Location','Best'); +title(leg,'Azimuth [deg]') +box on +grid on +xlim([0,90]) + +figure() +legInfoEle=cell(length(ele),1); +hold on +for i=1:length(ele) + plot(azi,eff_data(:,i),'LineWidth',LineWidth); + legInfoEle{i}=num2str(ele(i)); +end +hold off +xlabel('Azimuth Angle [deg]') +ylabel('Solarfield Efficiency [-]') +set(gca,'FontSize',FontSize) +leg=legend(legInfoEle,'NumColumns',2,'Location','Best'); +title(leg,'Elevation [deg]') +xlim([0,360]) +box on +grid on + diff --git a/deploy/api/min_example.m b/deploy/api/min_example.m new file mode 100644 index 0000000..1e732e8 --- /dev/null +++ b/deploy/api/min_example.m @@ -0,0 +1,49 @@ +% If current folder is .\source\solarpilot_dev\solarpilot\deploy\api then +% the only path needed is the location of the TMY and can be local. +TMY_file="..\climate_files\USA CA Daggett (TMY2).csv"; +cp = py.copylot.CoPylot(); + +% If current folder is any other folder then you have to provide the path +% where copylot.py and solarpilot.dll are placed, and the TMY needs the full path. +% Uncomment the following lines in that case. +% CoPylot_path='C:\Users\adelacal\source\solarpilot_dev\solarpilot\deploy\api'; +% TMY_file="C:\Users\adelacal\source\solarpilot_dev\solarpilot\deploy\climate_files\USA CA Daggett (TMY2).csv"; +% +% if count(py.sys.path,CoPylot_path) == 0 +% insert(py.sys.path,int32(0),CoPylot_path); +% end +% cp = py.copylot.CoPylot(path=CoPylot_path); + +r = cp.data_create(); +cp.data_set_string(r,"ambient.0.weather_file",TMY_file); +cp.generate_layout(r); +field = cp.get_layout_info(r); +cp.simulate(r); +flux = cp.get_fluxmap(r); +res= cp.summary_results(r); +eff=res.get('Solar field optical efficiency') +cp.data_free(r); + +plot_results=true; +if plot_results + field.to_csv("field.csv"); + field_table=readtable("field.csv"); + delete("field.csv"); + colors=[0.0,0.4,0.7]; + figure() + scatter(field_table.x_location, field_table.y_location,... + "Marker","square","MarkerEdgeColor",colors,"MarkerFaceColor",colors,... + "SizeData",3); + box on + grid on + + fluxm=double(py.numpy.array(flux)); + figure() + imagesc(fluxm); + colorbar(); +end + + + + + diff --git a/deploy/api/test_script.m b/deploy/api/test_script.m new file mode 100644 index 0000000..feb78b9 --- /dev/null +++ b/deploy/api/test_script.m @@ -0,0 +1,407 @@ +%% Matlab test script +% If current folder is .\source\solarpilot_dev\solarpilot\deploy\api then +% the only path needed is the location of the TMY and can be local. +TMY_file="..\climate_files\USA CA Daggett (TMY2).csv"; +cp = py.copylot.CoPylot(); + +% If current folder is any other folder then you have to provide the path +% where copylot.py and solarpilot.dll are placed, and the TMY needs the full path. +% Uncomment the following lines in that case. +% CoPylot_path='C:\Users\adelacal\source\solarpilot_dev\solarpilot\deploy\api'; +% TMY_file="C:\Users\adelacal\source\solarpilot_dev\solarpilot\deploy\climate_files\USA CA Daggett (TMY2).csv"; +% if count(py.sys.path,CoPylot_path) == 0 +% insert(py.sys.path,int32(0),CoPylot_path); +% end +% cp = py.copylot.CoPylot(path=CoPylot_path); + +plot_results = true ; +test_solTrace_sim = true; + +%% Minimum working example -> Must update path to weather file +disp('Minimum working example') +r = cp.data_create(); +cp.api_callback_create(r); +cp.data_set_string(r,"ambient.0.weather_file",TMY_file); %Must provide a TMY file +cp.generate_layout(r); +field = cp.get_layout_info(r); +cp.simulate(r); +flux = cp.get_fluxmap(r); +cp.data_free(r); +cp.api_disable_callback(r) %#tested +disp('Minimum working example - Pass') + +%% Plotting (default) solar field and flux map +if plot_results + field.to_csv("field.csv"); + field_table=readtable("field.csv"); + figure() + colors=[0.0,0.4,0.7]; + scatter(field_table.x_location, field_table.y_location,... + "Marker","square","MarkerEdgeColor",colors,"MarkerFaceColor",colors,... + "SizeData",3); + fluxm=double(py.numpy.array(flux)); + figure() + imagesc(fluxm); + colorbar(); +end + + + +%% Testing set and get number - Pass +r = cp.data_create(); %# New SolarPILOT instance +py.print(cp.version(r)); %# Version number +%cp.api_callback_create(r) %# callback +%cp.api_disable_callback(r) %#tested +t1(1)=cp.data_set_number(r, "solarfield.0.dni_des", 1111.0); +t1(2)=isequal(cp.data_get_number(r, "solarfield.0.dni_des"),1111.0); +if all(t1) + disp('Testing set and get number - Pass') +else + disp('Testing set and get number - No Pass') +end +%% Testing set and get boolean - Pass +t2(1)=cp.data_set_number(r, "solarfield.0.is_sliprow_skipped", true); %# Works with True and False +t2(2)=cp.data_get_number(r, "solarfield.0.is_sliprow_skipped"); +t2(3)=cp.data_set_number(r, "solarfield.0.is_sliprow_skipped", 0.); %# Works with 1 and 0 +t2(4)=isequal(cp.data_get_number(r, "solarfield.0.is_sliprow_skipped"),false); + +if all(t2) + disp('Testing set and get boolean - Pass') +else + disp('Testing set and get boolean - No Pass') +end + +%% Testing set and get string - Pass +cp.data_set_string(r, "ambient.0.loc_state", "Mind"); %# - Pass +t3(1)=isequal(string(cp.data_get_string(r, "ambient.0.loc_state")),"Mind"); % # - Pass +t3(2)=not(cp.data_set_string(r, "ambient.0.sun_csr", "0.05"));% # - Not a string variable - Pass +if all(t3) + disp('Testing set and get string - Pass') +else + disp('Testing set and get string - No Pass') +end + +%% Testing setting and getting Combo variables - Through string - Pass +t4(1)=isequal(string(cp.data_get_string(r, "ambient.0.sun_type")),'Limb-darkened sun'); %# Default value +t4(2)=cp.data_set_string(r, "ambient.0.sun_type", "Gaussian sun"); %# Combo - acceptable option - Pass +t4(3)=isequal(string(cp.data_get_string(r, "ambient.0.sun_type")),"Gaussian sun"); +t4(4)=not(isequal(string(cp.data_get_string(r, "ambient.0.sun_type")),"aussian sun")); %# Combo - not acceptable option - Pass +t4(5)=isequal(string(cp.data_get_string(r, "ambient.0.sun_type")),"Gaussian sun");% # Value should not change +if all(t4) + disp('Testing setting and getting Combo variables - Through string - Pass') +else + disp('Testing setting and getting Combo variables - Through string - No Pass') +end + + +%% Testing setting and getting Combo variables - Through number - Pass +t5(1)=isequal(string(cp.data_get_string(r, "ambient.0.insol_type")),'Weather file data'); %# get string of combo choice +t5(2)=cp.data_set_number(r, "ambient.0.insol_type", 1); % # Combo - acceptable option - Pass +t5(3)=isequal(cp.data_get_number(r, "ambient.0.insol_type"),1); % # get number of combo choice +t5(4)=isequal(string(cp.data_get_string(r, "ambient.0.insol_type")),'Hottel model'); %# get string of combo choice +t5(5)=not(cp.data_set_number(r, "ambient.0.insol_type", 5)); %# Combo - not acceptable option - Pass +t5(6)=isequal(string(cp.data_get_string(r, "ambient.0.insol_type")),'Hottel model'); %# Value should not change +if all(t5) + disp('Testing set and get boolean - Pass') +else + disp('Testing set and get boolean - No Pass') +end +%% Testing set and get array - Pass +t6(1)=cp.data_set_array_from_csv(r, "financial.0.pmt_factors", "test_array.csv"); +t6(2)=isequal(length(double(cp.data_get_array(r, "financial.0.pmt_factors"))),9); +set_vector = [1.,2.,3.,4.,5.]; +t6(3)=cp.data_set_array(r, "financial.0.pmt_factors", set_vector); +ret_vector = double(cp.data_get_array(r, "financial.0.pmt_factors")); +t6(4)=isequal(set_vector,ret_vector); + +t6(5)=isequal(length(double(cp.data_get_array(r, "financial.0.schedule_array"))),8760); +t6(6)=cp.data_set_array(r, "financial.0.schedule_array", set_vector); %# testing set integer array - Pass +ret_vector = double(cp.data_get_array(r, "financial.0.schedule_array")); +t6(7)=isequal(set_vector,ret_vector); + +if all(t6) + disp('Testing set and get array - Pass') +else + disp('Testing set and get array - No Pass') +end + +%% Testing set and get matrix - Pass +set_matrix = [1, 1, 1, 1, 1; 2, 2, 2, 2, 2; 3, 3, 3, 3, 3; 4, 4, 4, 4, 4]; %matlab matrix + +%Matlab matrix to a python matrix +cstr = cell(1, size(set_matrix, 1)); +for row = 1:size(set_matrix, 1) + cstr(row) = {set_matrix(row, :)}; +end +set_matrix_python = py.numpy.array(cstr); + +t7(1)=cp.data_set_matrix(r, "ambient.0.atm_coefs", set_matrix_python); +ret_matrix = double(py.numpy.array(cp.data_get_matrix(r, "ambient.0.atm_coefs"))); +t7(2)=isequal(set_matrix,ret_matrix); %pass + +csv_matrix=table2array(readtable('test_matrix.csv')); +t7(3)=cp.data_set_matrix_from_csv(r, "ambient.0.atm_coefs", "test_matrix.csv"); +ret_matrix = double(py.numpy.array(cp.data_get_matrix(r, "ambient.0.atm_coefs"))); +t7(4)=isequal(csv_matrix,ret_matrix); %pass + +if all(t7) + disp('Testing set and get matrix - Pass') +else + disp('Testing set and get matrix - No Pass') +end + +%% Testing variable reset - Pass +cp.reset_vars(r); +t8(1)=isequal(cp.data_get_number(r, "solarfield.0.dni_des"),950); + +if all(t8) + disp('Testing variable reset - Pass') +else + disp('Testing variable reset - No Pass') +end + +%% Testing add and drop receiver - Pass +t9(1)=isequal(double(cp.add_receiver(r, "test_rec")),1); % # Second Receiver +t9(2)=isequal(double(cp.add_receiver(r, "test_rec")),-1); %# can't add another receiver with the same name +t9(3)=cp.drop_receiver(r, "test_rec"); +t9(4)=not(cp.drop_receiver(r, "test_rec")); %# can't drop receiver because is alredy dropped + +if all(t8) + disp('Testing add and drop receiver - Pass') +else + disp('Testing add and drop receiver - No Pass') +end + +%% Testing add and drop heliostat template - Pass +t10(1)=isequal(double(cp.add_heliostat_template(r, "test_helio")),1); %second heliostat template +t10(2)=isequal(double(cp.add_heliostat_template(r, "test_helio")),-1); %can't add another heliostat template with the same name +t10(3)=cp.drop_heliostat_template(r, "test_helio"); +t10(4)=not(cp.drop_heliostat_template(r, "test_heli")); %# can't drop heliostat templante with wrong name + +if all(t10) + disp('Testing add and drop heliostat template - Pass') +else + disp('Testing add and drop heliostat template - No Pass') +end +%% Testing generate and assign layout - Pass +cp.reset_vars(r); +cp.data_set_number(r, "solarfield.0.q_des", 100) ; % # Small field for debugging +cp.data_set_string(r, "receiver.0.rec_type", "Flat plate"); +cp.data_set_string(r,"ambient.0.weather_file",TMY_file); + +% generate - Pass +t11(1)=cp.data_set_string(r, "solarfield.0.des_sim_detail", "Single simulation point"); % # to speed up solution time for testing +t11(2)=cp.data_set_number(r, "solarfield.0.is_sliprow_skipped", true); +t11(3)=cp.data_set_number(r, "solarfield.0.slip_plane_blocking", 0.0); + +%## If you add a another template and do not choose a temp_which -> ERROR +%cp.add_heliostat_template(r, "test_helio") +% ## Requires setting heliostat template to use for field generation +% cp.data_set_string(r, "solarfield.0.temp_which", "Template 1") +% %# Test - Use single template - Pass +% %# Test - Specified range - Pass +% cp.add_heliostat_template(r, "Template 2") +% cp.data_set_number(r, "heliostat.0.height", 6.) +% cp.data_set_number(r, "heliostat.0.width", 6.) +% cp.data_set_number(r, "heliostat.0.temp_rad_max", 500) +% cp.data_set_number(r, "heliostat.1.temp_rad_min", 500) +% cp.data_set_number(r, "heliostat.1.temp_rad_max", 2000) +% cp.data_set_string(r, "solarfield.0.template_rule", "Specified range") +% %# Test - Even radial distribution - Pass +% cp.add_heliostat_template(r, "Template 2") +% cp.data_set_number(r, "heliostat.0.height", 6.) +% cp.data_set_number(r, "heliostat.0.width", 6.) +% cp.data_set_string(r, "solarfield.0.template_rule", "Even radial distribution") +% cp.generate_layout(r, nthreads=py.int(4)) %# Testing - Pass + + +%assign +%pulling in heliostat locations +csvDataFile=readtable("test_field.csv"); +helio_data=py.list(); +for i=1:height(csvDataFile) + helio_data.append(csvDataFile{i,:}) +% helio_data.append(py.numpy.array(csvDataFile{i,:})) +end +t11(4)=cp.assign_layout(r, helio_data); % # Testing - Pass +% +% # Changing flux map resolution +t11(5)=cp.generate_layout(r); +t11(6)=cp.data_set_number(r, "fluxsim.0.x_res", 45); +t11(7)=cp.data_set_number(r, "fluxsim.0.y_res", 30); +t11(8)=cp.simulate(r); +flux_hermite = cp.get_fluxmap(r); %# Testing - Pass + +%Plotting flux map +if plot_results + flux_hermite_matlab=double(py.numpy.array(flux_hermite)); + figure() + imagesc(flux_hermite_matlab); + colorbar(); + title('Hermite Results') +end + +if all(t11) + disp('Testing generate and assign layout - Pass') +else + disp('Testing generate and assign layout - No Pass') +end + + +%% SolTrace simulation +if test_solTrace_sim + t12(1)=cp.data_set_string(r, "fluxsim.0.flux_model", "SolTrace"); %# Tested + t12(2)=cp.data_set_string(r, "fluxsim.0.aim_method", "Keep existing"); + t12(3)=cp.data_set_number(r, "fluxsim.0.max_rays", 100000000); + t12(4)=cp.data_set_number(r, "fluxsim.0.min_rays", 1000000); + t12(5)=cp.simulate(r); %# Testing - Pass + flux_ST = cp.get_fluxmap(r); %# Testing - Pass + + % # Change back for rest of tests + t12(6)=cp.data_set_string(r, "fluxsim.0.flux_model", "Hermite (analytical)"); + t12(7)=cp.data_set_string(r, "fluxsim.0.aim_method", "Image size priority"); +% +% # Plotting flux map + if plot_results + flux_ST_matlab=double(py.numpy.array(flux_ST)); + figure() + imagesc(flux_ST_matlab); + colorbar(); + title('SolTrace Results'); + end + if all(t12) + disp('Testing SolTrace simulation - Pass') + else + disp('Testing SolTrace simulation - No Pass') + end +end +%% Testing update layout - Pass +% ##check = cp.add_land(r, b'exclus', [[1000, 1000],[500,1000], [500,500], [1000, 500]]) # - Testing - Pass + + +res = cp.detail_results(r); +res.to_csv('res.csv'); +res_table=readtable('res.csv'); +delete('res.csv'); +helio_dict = py.dict(pyargs(... + "id", [res_table.id(1),res_table.id(2)], ... + "location-x", [1500, -1500],... + "location-y", [1500, 1500],... + "soiling" , [0.5, 0.3],... + "reflectivity", [0.2, 0.8],... + "enabled", [1, 0])); +t13(1)=cp.modify_heliostats(r, helio_dict); + +% find max flux of original geometry +t13(2)=cp.simulate(r); %# Testing - Pass +flux = cp.get_fluxmap(r); +flux_matlab=double(py.numpy.array(flux)); +maxflux_befc = max(flux_matlab,[],'all'); + +% Change geometry, simulate, find max flux +t13(3)=cp.data_set_number(r, "heliostat.0.height", 11.0); +t13(4)=cp.simulate(r); +flux = cp.get_fluxmap(r); +flux_matlab=double(py.numpy.array(flux)); +maxflux_aftc_noUP = max(flux_matlab,[],'all'); + +%Update, simulate, and find max flux +t13(5)=cp.update_geometry(r); %# Testing - Pass +t13(6)=cp.simulate(r); +flux = cp.get_fluxmap(r); +flux_matlab=double(py.numpy.array(flux)); +maxflux_aftu = max(flux_matlab,[],'all'); + +t13(7)=isequal(length(unique([maxflux_befc, maxflux_aftc_noUP,maxflux_aftu])),3); + +if all(t13) + disp('Testing update layout - Pass ') +else + disp('Testing update layout - No Pass') +end + +%% Testing get results - pass: +res1 = cp.summary_results(r, save_dict=true); %# Testing - Pass +Nhel=res1.get('Simulated heliostat count'); +t14(1)=isequal(Nhel,1172); + +%[res, header] = cp.detail_results(r, restype = 'matrix') %# returns (matrix, header) - Pass +% res = cp.detail_results(r, restype = 'matrix') % # returns (matrix, header) - Pass +% res = cp.detail_results(r, restype = 'dictionary') %# returns dictionary - Pass + +res2 = cp.detail_results(r, get_corners=true); %# returns dataframe - Pass + +%Dataframe to table throught csv +res2.to_csv("res2.csv"); +res2_table=readtable("res2.csv"); +delete("res2.csv"); +t14(2)=isequal(height(res2_table),Nhel); + +set_matrix = [500, 500; 1000, 1000; 500, 1000]; %matlab matrix +%Matlab matrix to a python matrix +cstr = cell(1, size(set_matrix, 1)); +for row = 1:size(set_matrix, 1) + cstr(row) = {set_matrix(row, :)}; +end +set_matrix_python = py.numpy.array(cstr); +res3 = cp.heliostats_by_region(r, coor_sys="polygon", arguments=set_matrix_python); %# tested all, cylindrical, cartesian, and polygon - Pass +% res3.to_csv("res3.csv"); +% res3_table=readtable("res3.csv"); +% delete("res3.csv"); + +if all(t14) + disp('Testing get results - Pass ') +else + disp('Testing get results - No Pass') +end + +%% Testing modify_heliostats by disabling half the field and re-simulating - Pass + +cp.simulate(r); %# Testing - Pass +flux = cp.get_fluxmap(r); +flux_matlab=double(py.numpy.array(flux)); +maxflux_original=max(flux_matlab,[],'all'); +Nhel_half=round((Nhel/2),0); +helio_dict = py.dict(pyargs(... + "id", [res2_table.id(Nhel_half:end)], ... + "enabled", [zeros(length(res2_table.id(Nhel_half:end)),1)])); +t15(1)=cp.modify_heliostats(r, helio_dict ); %# Testing - Pass +t15(2)=cp.simulate(r); %# Testing - Pass +flux = cp.get_fluxmap(r); +flux_matlab=double(py.numpy.array(flux)); +maxflux_updated=max(flux_matlab,[],'all'); +if plot_results + figure() + imagesc(flux_matlab); + colorbar(); + title('Half field Results'); +end +t15(3)=not(isequal(maxflux_original,maxflux_updated)); +if all(t15) + disp('Testing modify_heliostats by disabling half the field and re-simulating - Pass ') +else + disp('Testing modify_heliostats by disabling half the field and re-simulating - No Pass') +end +% +% # Pulling field data +%field,header = cp.get_layout_info(r, get_corners=true, restype="matrix"); %# Testing - No Pass +%cp.clear_land(r, clear_type=b'inclusion') %# Testing - Pass +%cp.clear_land(r, clear_type='inclusion'); %# Testing - Pass + +%% Testing dump_varmap and save_from script - Pass +cp.dump_varmap_tofile(r, "varmap_dump_v2.csv"); %# This does not work - must provide full path +t16(1)=cp.dump_varmap_tofile(r, "./varmap_dump_v2.csv"); %works with the ./ +cp.data_set_number(r, "solarfield.0.dni_des", 1111); +t16(2)=cp.save_from_script(r, "./case_study_v2.spt"); +cp.data_free(r); + +r = cp.data_create(); +t16(3)=cp.load_from_script(r, "case_study_v2.spt"); +t16(4)=isequal(cp.data_get_number(r, "solarfield.0.dni_des"),1111); %# Testing if variable value loads correctly +cp.data_free(r); % Works - free memory + +if all(t16) + disp('Testing dump_varmap and save_from script - Pass ') +else + disp('Testing dump_varmap and save_from script - No Pass') +end From 034a2431fb24ca7222632d6852899b91fde30be7 Mon Sep 17 00:00:00 2001 From: Alberto de la Calle <95384970+adlcalle@users.noreply.github.com> Date: Mon, 16 May 2022 11:25:35 -0700 Subject: [PATCH 2/2] Path as input in init Allows add a path to init to work from other folders --- deploy/api/copylot.py | 2347 +++++++++++++++++++++-------------------- 1 file changed, 1175 insertions(+), 1172 deletions(-) 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 - [