@@ -512,143 +512,6 @@ Generate polar data for aerodynamic analysis over a range of angles.
512512# Returns
513513- Tuple of polar data array and Reynolds number
514514"""
515- function generate_polar_data (
516- solver,
517- body_aero:: BodyAerodynamics ,
518- angle_range;
519- angle_type= " angle_of_attack" ,
520- angle_of_attack= 0.0 ,
521- side_slip= 0.0 ,
522- v_a= 10.0 ,
523- use_latex= false
524- )
525- _ = use_latex
526-
527- n_panels = length (body_aero. panels)
528- n_angles = length (angle_range)
529-
530- # Initialize arrays
531- cl = zeros (n_angles)
532- cd = zeros (n_angles)
533- cs = zeros (n_angles)
534- cmx = fill (NaN , n_angles)
535- cmy = fill (NaN , n_angles)
536- cmz = fill (NaN , n_angles)
537- gamma_distribution = zeros (n_angles, n_panels)
538- cl_distribution = zeros (n_angles, n_panels)
539- cd_distribution = zeros (n_angles, n_panels)
540- cs_distribution = zeros (n_angles, n_panels)
541- reynolds_number = zeros (n_angles)
542-
543- for (i, angle_i) in enumerate (angle_range)
544- # Set angle based on type
545- if angle_type == " angle_of_attack"
546- α = deg2rad (angle_i)
547- β = side_slip
548- elseif angle_type == raw " side_slip"
549- α = angle_of_attack
550- β = deg2rad (angle_i)
551- else
552- throw (ArgumentError (
553- " angle_type must be 'angle_of_attack' or 'side_slip'" ))
554- end
555-
556- # Update inflow conditions
557- set_va! (
558- body_aero,
559- [
560- cos (α) * cos (β),
561- sin (β),
562- sin (α)
563- ] * v_a
564- )
565-
566- # Solve and store results
567- results = solve (solver, body_aero, gamma_distribution[i, :])
568-
569- cl[i] = results[" cl" ]
570- cd[i] = results[" cd" ]
571- cs[i] = results[" cs" ]
572- cmx[i] = get (results, " cmx" , NaN )
573- cmy[i] = get (results, " cmy" , NaN )
574- cmz[i] = get (results, " cmz" , NaN )
575- gamma_distribution[i, :] = results[" gamma_distribution" ]
576- cl_distribution[i, :] = results[" cl_distribution" ]
577- cd_distribution[i, :] = results[" cd_distribution" ]
578- cs_distribution[i, :] = results[" cs_distribution" ]
579- reynolds_number[i] = results[" Rey" ]
580- end
581-
582- polar_data = [
583- angle_range,
584- cl,
585- cd,
586- cs,
587- gamma_distribution,
588- cl_distribution,
589- cd_distribution,
590- cs_distribution,
591- reynolds_number
592- ]
593-
594- return (polar_data= polar_data, cmx= cmx, cmy= cmy, cmz= cmz,
595- rey= reynolds_number[1 ])
596- end
597-
598- function _extract_literature_polar_data (raw_data, path;
599- angle_type= " angle_of_attack" )
600- table, header = if raw_data isa Tuple
601- # readdlm(...; header=true) returns (data, header)
602- raw_table, raw_header = raw_data
603- raw_table, lowercase .(strip .(string .(vec (raw_header))))
604- else
605- # Header is in first row when a single matrix is returned
606- raw_data[2 : end , :], lowercase .(strip .(string .(raw_data[1 , :])))
607- end
608-
609- # Find angle column based on angle_type
610- alpha_idx = if angle_type == " side_slip"
611- findfirst (
612- x -> occursin (" beta" , x) ||
613- occursin (" side_slip" , x), header)
614- else
615- findfirst (
616- x -> occursin (" alpha" , x) || x == " aoa" , header)
617- end
618- cl_idx = findfirst (x -> occursin (" cl" , x), header)
619- cd_idx = findfirst (x -> occursin (" cd" , x), header)
620- cs_idx = findfirst (x -> occursin (" cs" , x), header)
621- cmx_idx = findfirst (x -> occursin (" cmx" , x), header)
622- cmy_idx = findfirst (x -> occursin (" cmy" , x), header)
623- cmz_idx = findfirst (x -> occursin (" cmz" , x), header)
624-
625- (isnothing (alpha_idx) || isnothing (cl_idx) || isnothing (cd_idx)) &&
626- throw (ArgumentError (
627- " Literature CSV must contain alpha/aoa, cl and cd " *
628- " columns: $path " ))
629-
630- n_rows = size (table, 1 )
631- cs_col = cs_idx === nothing ?
632- zeros (n_rows) : table[:, cs_idx]
633- cmx_col = cmx_idx === nothing ?
634- fill (NaN , n_rows) : table[:, cmx_idx]
635- cmy_col = cmy_idx === nothing ?
636- fill (NaN , n_rows) : table[:, cmy_idx]
637- cmz_col = cmz_idx === nothing ?
638- fill (NaN , n_rows) : table[:, cmz_idx]
639-
640- return (
641- polar_data= [
642- table[:, alpha_idx],
643- table[:, cl_idx],
644- table[:, cd_idx],
645- cs_col
646- ],
647- cmx= cmx_col,
648- cmy= cmy_col,
649- cmz= cmz_col
650- )
651- end
652515
653516"""
654517 plot_polars(solver_list, body_aero_list, label_list;
@@ -712,7 +575,7 @@ function VortexStepMethod.plot_polars(
712575 polar_data_list = []
713576 cm_data_list = []
714577 for (i, (solver, body_aero)) in enumerate (zip (solver_list, body_aero_list))
715- result = generate_polar_data (
578+ result = VortexStepMethod . generate_polar_data (
716579 solver, body_aero, angle_range;
717580 angle_type,
718581 angle_of_attack,
@@ -729,7 +592,7 @@ function VortexStepMethod.plot_polars(
729592 if ! isempty (literature_path_list)
730593 for path in literature_path_list
731594 raw_data = readdlm (path, ' ,' )
732- lit = _extract_literature_polar_data (
595+ lit = VortexStepMethod . extract_literature_polar_data (
733596 raw_data, path; angle_type)
734597 push! (polar_data_list, lit. polar_data)
735598 push! (cm_data_list, (cmx= lit. cmx, cmy= lit. cmy,
@@ -965,6 +828,7 @@ function VortexStepMethod.plot_combined_analysis(
965828 body_aero,
966829 results;
967830 solver_label= " VSM" ,
831+ labels= nothing ,
968832 angle_range= range (0 , 20 , length= 20 ),
969833 angle_type= " angle_of_attack" ,
970834 angle_of_attack= 0.0 ,
@@ -980,61 +844,79 @@ function VortexStepMethod.plot_combined_analysis(
980844 use_tex= false ,
981845 literature_path_list= String[],
982846 cl_over_cd= true ,
847+ angle_of_attack_for_spanwise_distribution= 5.0 ,
983848)
984849 # Normalize inputs to arrays for consistent handling
985850 solvers = solver isa Vector ? solver : [solver]
986851 body_aeros = body_aero isa Vector ? body_aero : [body_aero]
987852 results_list = results isa Vector ? results : [results]
988- labels = solver_label isa Vector ? solver_label : [solver_label]
853+ n_solvers = length (solvers)
854+ n_literature = length (literature_path_list)
855+
856+ # Label normalization (matches Makie version)
857+ label_source = isnothing (labels) ? solver_label : labels
858+ labels_in = label_source isa AbstractVector ?
859+ string .(label_source) : [string (label_source)]
860+ solver_labels = length (labels_in) == 1 ?
861+ fill (labels_in[1 ], n_solvers) :
862+ labels_in[1 : n_solvers]
863+
864+ # Compute spanwise results at specified AoA
865+ results_spanwise = copy (results_list)
866+ if ! isnothing (angle_of_attack_for_spanwise_distribution)
867+ α_span = deg2rad (
868+ angle_of_attack_for_spanwise_distribution)
869+ β_span = deg2rad (side_slip)
870+ for (i, (s, ba)) in enumerate (
871+ zip (solvers, body_aeros))
872+ va_old = copy (getfield (ba, :_va ))
873+ omega_old = copy (ba. omega)
874+ set_va! (ba, [cos (α_span) * cos (β_span),
875+ sin (β_span), sin (α_span)] * v_a)
876+ results_spanwise[i] = solve (s, ba,
877+ s. sol. gamma_distribution)
878+ set_va! (ba, va_old, omega_old)
879+ end
880+ end
989881
990- # Extract y-coordinates for distribution plot (use first body_aero)
991- body_y_coordinates = [panel. aero_center[2 ] for panel in body_aeros[1 ]. panels]
992- y_coords_list = [body_y_coordinates for _ in 1 : length (solvers)]
882+ # Extract y-coordinates for distribution plot
883+ y_coords_list = [
884+ [p. aero_center[2 ] for p in ba. panels]
885+ for ba in body_aeros]
993886
994- # Plot geometry (only use first body_aero)
887+ # Plot geometry (first body_aero only )
995888 plot_geometry (
996889 body_aeros[1 ],
997890 title;
998- data_type= data_type,
999- save_path= save_path,
1000- is_save= is_save,
1001- is_show= is_show,
1002- view_elevation= view_elevation,
1003- view_azimuth= view_azimuth,
1004- use_tex= use_tex
891+ data_type, save_path, is_save, is_show,
892+ view_elevation, view_azimuth, use_tex
1005893 )
1006894
1007895 # Plot spanwise distributions
1008896 plot_distribution (
1009897 y_coords_list,
1010- results_list ,
1011- labels ;
898+ results_spanwise ,
899+ solver_labels ;
1012900 title= title * " - Distributions" ,
1013- data_type= data_type,
1014- save_path= save_path,
1015- is_save= is_save,
1016- is_show= is_show,
1017- use_tex= use_tex
901+ data_type, save_path, is_save, is_show, use_tex
1018902 )
1019903
1020- # Plot polars
904+ # Plot polars (include literature labels)
905+ polar_labels = if n_literature > 0 &&
906+ length (labels_in) == n_solvers + n_literature
907+ labels_in
908+ else
909+ solver_labels
910+ end
1021911 plot_polars (
1022912 solvers,
1023913 body_aeros,
1024- labels;
1025- literature_path_list= literature_path_list,
1026- angle_range= angle_range,
1027- angle_type= angle_type,
1028- angle_of_attack= angle_of_attack,
1029- side_slip= side_slip,
1030- v_a= v_a,
914+ polar_labels;
915+ literature_path_list, angle_range, angle_type,
916+ angle_of_attack, side_slip, v_a,
1031917 title= title * " - Polars" ,
1032- data_type= data_type,
1033- save_path= save_path,
1034- is_save= is_save,
1035- is_show= is_show,
1036- use_tex= use_tex,
1037- cl_over_cd= cl_over_cd
918+ data_type, save_path, is_save, is_show,
919+ use_tex, cl_over_cd
1038920 )
1039921end
1040922
0 commit comments