11import numpy as np
2+ import scipy .optimize
3+ import shapely .affinity
24from shapely import Polygon
35
46from . import helpers
@@ -61,37 +63,6 @@ def roll_power(self: AsymmetricTwoRollPass):
6163 return self .upper_roll .roll_power + self .lower_roll .roll_power
6264
6365
64- @AsymmetricTwoRollPass .entry_point
65- def entry_point (self : AsymmetricTwoRollPass ):
66- height_change = self .in_profile .height - self .height
67- return (
68- np .sqrt (height_change )
69- * np .sqrt (
70- (2 * self .upper_roll .min_radius - height_change )
71- * (2 * self .lower_roll .min_radius - height_change )
72- * (2 * self .upper_roll .min_radius + 2 * self .lower_roll .min_radius - height_change )
73- )
74- ) / (2 * (self .upper_roll .min_radius + self .lower_roll .min_radius - height_change ))
75-
76-
77- @AsymmetricTwoRollPass .entry_point
78- def entry_point_square_oval (self : AsymmetricTwoRollPass ):
79- if "square" in self .in_profile .classifiers and "oval" in self .classifiers :
80- upper_depth = self .upper_roll .groove .local_depth (self .in_profile .width / 2 )
81- lower_depth = self .lower_roll .groove .local_depth (self .in_profile .width / 2 )
82- height_change = self .in_profile .height - self .gap - upper_depth - lower_depth
83- upper_radius = self .upper_roll .max_radius - upper_depth
84- lower_radius = self .lower_roll .max_radius - lower_depth
85- return (
86- np .sqrt (height_change )
87- * np .sqrt (
88- (2 * upper_radius - height_change )
89- * (2 * lower_radius - height_change )
90- * (2 * upper_radius + 2 * lower_radius - height_change )
91- )
92- ) / (2 * (upper_radius + lower_radius - height_change ))
93-
94-
9566@AsymmetricTwoRollPass .velocity
9667def velocity (self : AsymmetricTwoRollPass ):
9768 if self .upper_roll .has_value ("neutral_angle" ) and self .lower_roll .has_value ("neutral_angle" ):
@@ -111,3 +82,59 @@ def roll_force(self: AsymmetricTwoRollPass):
11182 * (self .upper_roll .contact_area + self .lower_roll .contact_area )
11283 / 2
11384 )
85+
86+
87+ @AsymmetricTwoRollPass .InProfile .pass_line
88+ def pass_line (self : AsymmetricTwoRollPass .InProfile ) -> tuple [float , float , float ]:
89+ rp = self .roll_pass
90+
91+ if not self .has_set ("pass_line" ):
92+ height_change = self .height - rp .height
93+ x_guess = - (
94+ np .sqrt (height_change )
95+ * np .sqrt (
96+ (2 * rp .upper_roll .min_radius - height_change )
97+ * (2 * rp .lower_roll .min_radius - height_change )
98+ * (2 * rp .upper_roll .min_radius + 2 * rp .lower_roll .min_radius - height_change )
99+ )
100+ ) / (2 * (rp .upper_roll .min_radius + rp .lower_roll .min_radius - height_change ))
101+ y_guess = 0
102+ else :
103+ x_guess , y_guess , _ = self .pass_line
104+
105+ def contact_objective (xy ):
106+ shifted_cross_section = shapely .affinity .translate (rp .rotated_in_profile .cross_section , yoff = xy [1 ])
107+
108+ upper_contour = shapely .geometry .LineString (np .stack ([
109+ rp .upper_roll .surface_z ,
110+ rp .upper_roll .surface_interpolation (xy [0 ], rp .upper_roll .surface_z ).squeeze (axis = 1 )
111+ ], axis = 1 ))
112+ upper_contour = shapely .affinity .translate (upper_contour ,yoff = self .roll_pass .gap / 2 )
113+ lower_contour = shapely .geometry .LineString (np .stack ([
114+ rp .lower_roll .surface_z ,
115+ rp .lower_roll .surface_interpolation (xy [0 ], rp .lower_roll .surface_z ).squeeze (axis = 1 )
116+ ], axis = 1 ))
117+ lower_contour = shapely .affinity .scale (shapely .affinity .translate (lower_contour , yoff = self .roll_pass .gap / 2 ), xfact = 1 , yfact = - 1 , origin = (0 ,0 ))
118+
119+ upper_intersection = shapely .intersection (upper_contour , shifted_cross_section )
120+ lower_intersection = shapely .intersection (lower_contour , shifted_cross_section )
121+
122+ upper_value = upper_intersection .length if not upper_intersection .is_empty else shapely .shortest_line (upper_contour , shifted_cross_section ).length
123+ lower_value = lower_intersection .length if not lower_intersection .is_empty else shapely .shortest_line (lower_contour , shifted_cross_section ).length
124+
125+ return upper_value ** 2 + lower_value ** 2
126+
127+ sol = scipy .optimize .minimize (contact_objective , (x_guess , y_guess ), method = "BFGS" , options = dict (xrtol = 1e-2 ))
128+
129+ return sol .x [0 ], sol .x [1 ], 0
130+
131+
132+ @AsymmetricTwoRollPass .InProfile .cross_section
133+ def in_cross_section (self :AsymmetricTwoRollPass .InProfile ):
134+ return shapely .affinity .translate (self .roll_pass .rotated_in_profile .cross_section , xoff = self .pass_line [2 ], yoff = self .pass_line [1 ])
135+
136+
137+ @AsymmetricTwoRollPass .entry_point
138+ def entry_point (self : AsymmetricTwoRollPass ):
139+ return self .in_profile .pass_line [0 ]
140+
0 commit comments