From fe0f6eebe42a631bf191f2eee7d7b5cd16c4ec48 Mon Sep 17 00:00:00 2001 From: Marco Mangano Date: Mon, 8 Feb 2021 12:54:20 +0100 Subject: [PATCH 01/18] added new vars for rotType0 scaling handling --- pygeo/DVGeometry.py | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/pygeo/DVGeometry.py b/pygeo/DVGeometry.py index cd6a67f7..7c915ce6 100644 --- a/pygeo/DVGeometry.py +++ b/pygeo/DVGeometry.py @@ -198,6 +198,7 @@ def __init__(self, fileName, complex=False, child=False, faceFreeze=None, name=N def addRefAxis(self, name, curve=None, xFraction=None, volumes=None, rotType=5, axis='x', alignIndex=None, rotAxisVar=None, + rot0ang=None, rot0axis=[1, 0, 0], xFractionOrder=2, includeVols=[], ignoreInd=[], raySize=1.5): """ @@ -268,6 +269,19 @@ def addRefAxis(self, name, curve=None, xFraction=None, volumes=None, variable which should be used to compute the orientation of the theta rotation. + rot0ang: float + If rotType == 0, defines the offset angle of the (child) FFD with respect + to the main system of reference. This is necessary to use the scaling functions + `scale_x`, `scale_y`, and `scale_z` with rotType == 0. The axis of rotation is + defined by `rot0axis`. + + rot0axis: list + If rotType == 0, defines the rotation axis for the rotation offset of the + FFD grid given by `rot0ang`. The variable has to be a list of 3 floats + defining the [x,y,z] components of the axis direction. + This is necessary to use the scaling functions `scale_x`, `scale_y`, + and `scale_z` with rotType == 0. + xFractionOrder : int Order of spline used for refaxis curve. @@ -325,7 +339,7 @@ def addRefAxis(self, name, curve=None, xFraction=None, volumes=None, if volumes is None: volumes = numpy.arange(self.FFD.nVol) self.axis[name] = {'curve':curve, 'volumes':volumes, - 'rotType':rotType, 'axis':axis} + 'rotType':rotType, 'axis':axis, 'rot0ang':rot0ang, 'rot0axis':rot0axis} else: # get the direction of the symmetry plane @@ -349,9 +363,9 @@ def addRefAxis(self, name, curve=None, xFraction=None, volumes=None, for coef in curveSymm.coef: curveSymm.coef[:,index]=-curveSymm.coef[:,index] self.axis[name] = {'curve':curve, 'volumes':volumes, - 'rotType':rotType, 'axis':axis} + 'rotType':rotType, 'axis':axis,'rot0ang':rot0ang, 'rot0axis':rot0axis} self.axis[name+'Symm'] = {'curve':curveSymm, 'volumes':volumesSymm, - 'rotType':rotType, 'axis':axis} + 'rotType':rotType, 'axis':axis, 'rot0ang':rot0ang, 'rot0axis':rot0axis} nAxis = len(curve.coef) elif xFraction is not None: # Some assumptions @@ -437,7 +451,7 @@ def addRefAxis(self, name, curve=None, xFraction=None, volumes=None, curve = pySpline.Curve(X=refaxisNodes, k=2) nAxis = len(curve.coef) self.axis[name] = {'curve':curve, 'volumes':volumes, - 'rotType':rotType, 'axis':axis, + 'rotType':rotType, 'axis':axis, 'rot0ang':rot0ang, 'rot0axis':rot0axis, 'rotAxisVar':rotAxisVar} else: raise Error("One of 'curve' or 'xFraction' must be " @@ -1188,6 +1202,12 @@ def updateCalculations(self, new_pts, isComplex, config): for ipt in range(self.nPtAttach): base_pt = self.refAxis.curves[self.curveIDs[ipt]](self.links_s[ipt]) + # Variables for rotType = 0 rotation + scaling + ang = self.axis[self.curveIDNames[ipt]]['rot0ang'] + ax_dir = self.axis[self.curveIDNames[ipt]]['rot0axis'] + if ang: + ang *= numpy.pi/180 # conv to [rad] + scale = self.scale[self.curveIDNames[ipt]](self.links_s[ipt]) scale_x = self.scale_x[self.curveIDNames[ipt]](self.links_s[ipt]) scale_y = self.scale_y[self.curveIDNames[ipt]](self.links_s[ipt]) From 027d285c0839bb517d3cdbb52ea2b9c0bcb1701d Mon Sep 17 00:00:00 2001 From: Marco Mangano Date: Mon, 8 Feb 2021 15:30:06 +0100 Subject: [PATCH 02/18] applying axis scaling to rot0 - Mads way --- pygeo/DVGeometry.py | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/pygeo/DVGeometry.py b/pygeo/DVGeometry.py index 7c915ce6..c544ccf5 100644 --- a/pygeo/DVGeometry.py +++ b/pygeo/DVGeometry.py @@ -1205,8 +1205,12 @@ def updateCalculations(self, new_pts, isComplex, config): # Variables for rotType = 0 rotation + scaling ang = self.axis[self.curveIDNames[ipt]]['rot0ang'] ax_dir = self.axis[self.curveIDNames[ipt]]['rot0axis'] + bp_ = numpy.copy(base_pt) # copy of original pointset - will not be rotated if ang: ang *= numpy.pi/180 # conv to [rad] + # Rotating the FFD according to inputs + # The FFD points should now be aligned with the main system of reference + base_pt = geo_utils.rotVbyW(bp_, ax_dir, ang) scale = self.scale[self.curveIDNames[ipt]](self.links_s[ipt]) scale_x = self.scale_x[self.curveIDNames[ipt]](self.links_s[ipt]) @@ -1222,9 +1226,30 @@ def updateCalculations(self, new_pts, isComplex, config): new_vec = geo_utils.rotVbyW(new_vec, deriv, self.rot_theta[ self.curveIDNames[ipt]](self.links_s[ipt])*numpy.pi/180) if isComplex: - new_pts[ipt] = base_pt + new_vec*scale + new_pts[ipt] = bp_ + new_vec*scale # using "unrotated" bp_ vector else: - new_pts[ipt] = numpy.real(base_pt + new_vec*scale) + new_pts[ipt] = numpy.real(bp_ + new_vec*scale) + + if ang: + # Rotating to be aligned with main sys ref + nv_ = numpy.copy(new_vec) + new_vec = geo_utils.rotVbyW(nv_, ax_dir, ang) + + # Apply scaling + new_vec[0] *= scale_x + new_vec[1] *= scale_y + new_vec[2] *= scale_z + + if ang: + # Rotating back the scaled pointset to its original position + nv_rot = numpy.copy(new_vec) # nv_rot is scaled and rotated + new_vec = geo_utils.rotVbyW(nv_rot ,ax_dir,-ang) + + + if isComplex: + new_pts[ipt] = bp_ + new_vec + else: + new_pts[ipt] = numpy.real(bp_ + new_vec) else: rotX = geo_utils.rotxM(self.rot_x[ From f49f010d08ecf0560120d69b9a5e9e3e980ef67a Mon Sep 17 00:00:00 2001 From: Marco Mangano Date: Mon, 8 Feb 2021 17:51:52 +0100 Subject: [PATCH 03/18] extended nonaligned scaling to all rotTypes --- pygeo/DVGeometry.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/pygeo/DVGeometry.py b/pygeo/DVGeometry.py index c544ccf5..f8271a00 100644 --- a/pygeo/DVGeometry.py +++ b/pygeo/DVGeometry.py @@ -1243,7 +1243,7 @@ def updateCalculations(self, new_pts, isComplex, config): if ang: # Rotating back the scaled pointset to its original position nv_rot = numpy.copy(new_vec) # nv_rot is scaled and rotated - new_vec = geo_utils.rotVbyW(nv_rot ,ax_dir,-ang) + new_vec = geo_utils.rotVbyW(nv_rot , ax_dir, -ang) if isComplex: @@ -1260,6 +1260,10 @@ def updateCalculations(self, new_pts, isComplex, config): self.curveIDNames[ipt]](self.links_s[ipt])) D = self.links_x[ipt] + if ang: + # rotate non-aligned FFDs + D_ = numpy.copy(D) + D = geo_utils.rotVbyW(D_, ax_dir, ang) rotM = self._getRotMatrix(rotX, rotY, rotZ, rotType) @@ -1291,6 +1295,13 @@ def updateCalculations(self, new_pts, isComplex, config): D[0] *= scale_x D[1] *= scale_y D[2] *= scale_z + if ang: + # rotate non-aligned FFDs back to initial position + D_ = numpy.copy(D) + bp_rot = numpy.copy(base_pt) # here base_pt has been rotated + D = geo_utils.rotVbyW(D_ , ax_dir, -ang) + base_pt = geo_utils.rotVbyW(bp_rot, ax_dir, -ang) + if isComplex: new_pts[ipt] = base_pt + D*scale else: From 86cf8d102b0d8a262ee43f417c6e07149acb9cfd Mon Sep 17 00:00:00 2001 From: Marco Mangano Date: Mon, 8 Feb 2021 17:55:18 +0100 Subject: [PATCH 04/18] added WARNING - nonzero rotType have inaccurate sensitivities --- pygeo/DVGeometry.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pygeo/DVGeometry.py b/pygeo/DVGeometry.py index f8271a00..8d90eccd 100644 --- a/pygeo/DVGeometry.py +++ b/pygeo/DVGeometry.py @@ -1261,6 +1261,7 @@ def updateCalculations(self, new_pts, isComplex, config): D = self.links_x[ipt] if ang: + raise Warning("if rot0ang != 0, use rotType=0. The derivatives with other rotations are slightly off") # rotate non-aligned FFDs D_ = numpy.copy(D) D = geo_utils.rotVbyW(D_, ax_dir, ang) From 24d56c0094690ff30c530c19bdf2e42f473b7c3a Mon Sep 17 00:00:00 2001 From: Marco Mangano Date: Thu, 11 Feb 2021 19:32:02 +0100 Subject: [PATCH 05/18] bugfix on single axis scaling --- pygeo/DVGeometry.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pygeo/DVGeometry.py b/pygeo/DVGeometry.py index 8d90eccd..a99364ee 100644 --- a/pygeo/DVGeometry.py +++ b/pygeo/DVGeometry.py @@ -1223,8 +1223,6 @@ def updateCalculations(self, new_pts, isComplex, config): self.curveIDs[ipt]].getDerivative(self.links_s[ipt]) deriv /= geo_utils.euclideanNorm(deriv) # Normalize new_vec = -numpy.cross(deriv, self.links_n[ipt]) - new_vec = geo_utils.rotVbyW(new_vec, deriv, self.rot_theta[ - self.curveIDNames[ipt]](self.links_s[ipt])*numpy.pi/180) if isComplex: new_pts[ipt] = bp_ + new_vec*scale # using "unrotated" bp_ vector else: @@ -1245,6 +1243,7 @@ def updateCalculations(self, new_pts, isComplex, config): nv_rot = numpy.copy(new_vec) # nv_rot is scaled and rotated new_vec = geo_utils.rotVbyW(nv_rot , ax_dir, -ang) + new_vec = geo_utils.rotVbyW(new_vec, deriv, self.rot_theta[self.curveIDNames[ipt]](self.links_s[ipt])*numpy.pi/180) if isComplex: new_pts[ipt] = bp_ + new_vec From 36ed7072c292ac0ed7f6fa3d03b8ef986d6dd2f9 Mon Sep 17 00:00:00 2001 From: Marco Mangano Date: Mon, 15 Feb 2021 11:38:53 +0100 Subject: [PATCH 06/18] generalized axis nodes xyz location --- pygeo/DVGeometry.py | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/pygeo/DVGeometry.py b/pygeo/DVGeometry.py index a99364ee..b895fff5 100644 --- a/pygeo/DVGeometry.py +++ b/pygeo/DVGeometry.py @@ -196,7 +196,7 @@ def __init__(self, fileName, complex=False, child=False, faceFreeze=None, name=N tmp[ind] = True self.masks = tmp - def addRefAxis(self, name, curve=None, xFraction=None, volumes=None, + def addRefAxis(self, name, curve=None, xFraction=None, yFraction=None, zFraction=None, volumes=None, rotType=5, axis='x', alignIndex=None, rotAxisVar=None, rot0ang=None, rot0axis=[1, 0, 0], xFractionOrder=2, includeVols=[], ignoreInd=[], @@ -282,7 +282,7 @@ def addRefAxis(self, name, curve=None, xFraction=None, volumes=None, This is necessary to use the scaling functions `scale_x`, `scale_y`, and `scale_z` with rotType == 0. - xFractionOrder : int + xFractionOrder : int (NOT USED?) Order of spline used for refaxis curve. includeVols : list @@ -367,7 +367,7 @@ def addRefAxis(self, name, curve=None, xFraction=None, volumes=None, self.axis[name+'Symm'] = {'curve':curveSymm, 'volumes':volumesSymm, 'rotType':rotType, 'axis':axis, 'rot0ang':rot0ang, 'rot0axis':rot0axis} nAxis = len(curve.coef) - elif xFraction is not None: + elif xFraction or yFraction or zFraction: # Some assumptions # - FFD should be a close approximation of geometry surface so that # xFraction roughly corresponds to airfoil LE, TE, or 1/4 chord @@ -377,6 +377,14 @@ def addRefAxis(self, name, curve=None, xFraction=None, volumes=None, # included # - 'x' is streamwise direction + # Default to "mean" ref axis location along non-user specified direction + if xFraction is None: + xFraction = 0.5 + if yFraction is None: + yFraction = 0.5 + if zFraction is None: + zFraction = 0.5 + # This is the block direction along which the reference axis will lie # alignIndex = 'k' if alignIndex is None: @@ -430,16 +438,22 @@ def addRefAxis(self, name, curve=None, xFraction=None, volumes=None, # Loop through sections and compute node location place = 0 for j, vol in enumerate(volOrd): + # sectionArr: indices of FFD points grouped by section sectionArr = numpy.rollaxis(lIndex[vol], alignIndex, 0) skip = 0 if j > 0: skip = 1 for i in range(nSections[j]): - LE = numpy.min(self.FFD.coef[sectionArr[i+skip,:,:],0]) - TE = numpy.max(self.FFD.coef[sectionArr[i+skip,:,:],0]) - refaxisNodes[place+i,0] = xFraction*(TE - LE) + LE - refaxisNodes[place+i,1] = numpy.mean(self.FFD.coef[sectionArr[i+skip,:,:],1]) - refaxisNodes[place+i,2] = numpy.mean(self.FFD.coef[sectionArr[i+skip,:,:],2]) + x_min = numpy.min(self.FFD.coef[sectionArr[i+skip,:,:],0]) + x_max = numpy.max(self.FFD.coef[sectionArr[i+skip,:,:],0]) + y_min = numpy.min(self.FFD.coef[sectionArr[i+skip,:,:],1]) + y_max = numpy.max(self.FFD.coef[sectionArr[i+skip,:,:],1]) + z_min = numpy.min(self.FFD.coef[sectionArr[i+skip,:,:],2]) + z_max = numpy.max(self.FFD.coef[sectionArr[i+skip,:,:],2]) + + refaxisNodes[place+i,0] = xFraction * (x_max - x_min) + x_min # chordwise + refaxisNodes[place+i,1] = y_max - yFraction * (y_max - y_min) # top-bottom + refaxisNodes[place+i,2] = z_max - zFraction * (z_max - z_min) # top-bottom place += i + 1 # Add additional volumes From 42b7d61b36b54ab6ab2f38deb0f8e7506f6558f0 Mon Sep 17 00:00:00 2001 From: Marco Mangano Date: Mon, 15 Feb 2021 12:49:48 +0100 Subject: [PATCH 07/18] implemented Mads-Sandy fix for rotAxisnodes when ffds are not aligned to the main sys ref --- pygeo/DVGeometry.py | 49 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 39 insertions(+), 10 deletions(-) diff --git a/pygeo/DVGeometry.py b/pygeo/DVGeometry.py index b895fff5..7aade080 100644 --- a/pygeo/DVGeometry.py +++ b/pygeo/DVGeometry.py @@ -444,16 +444,45 @@ def addRefAxis(self, name, curve=None, xFraction=None, yFraction=None, zFraction if j > 0: skip = 1 for i in range(nSections[j]): - x_min = numpy.min(self.FFD.coef[sectionArr[i+skip,:,:],0]) - x_max = numpy.max(self.FFD.coef[sectionArr[i+skip,:,:],0]) - y_min = numpy.min(self.FFD.coef[sectionArr[i+skip,:,:],1]) - y_max = numpy.max(self.FFD.coef[sectionArr[i+skip,:,:],1]) - z_min = numpy.min(self.FFD.coef[sectionArr[i+skip,:,:],2]) - z_max = numpy.max(self.FFD.coef[sectionArr[i+skip,:,:],2]) - - refaxisNodes[place+i,0] = xFraction * (x_max - x_min) + x_min # chordwise - refaxisNodes[place+i,1] = y_max - yFraction * (y_max - y_min) # top-bottom - refaxisNodes[place+i,2] = z_max - zFraction * (z_max - z_min) # top-bottom + # getting all the section control points coordinates + pts_tens = self.FFD.coef[sectionArr[i + skip, :, :], :] # shape=(A,B,3) + # reshaping into vector to allow rotation (if needed) + pts_vec = numpy.copy(pts_tens.reshape(numpy.shape(pts_tens)[0] * numpy.shape(pts_tens)[1], 3)) # shape=(A*B,3) + + if rotType == 0 and rot0ang: + # rotating the FFD to be aligned with main axes + for ct_ in range(numpy.shape(pts_vec)[0]): + # here we loop over the pts_vec, rotate them and insert them inplace in pts_vec again + p_ = numpy.copy(pts_vec[ct_ , :]) + p_rot = geo_utils.rotVbyW(p_, rot0axis, numpy.pi / 180 * (rot0ang)) + pts_vec[ct_ , :] = p_rot + + # getting the bounds of the FFD section + x_min = numpy.min(pts_vec[:, 0]) + x_max = numpy.max(pts_vec[:, 0]) + y_min = numpy.min(pts_vec[:, 1]) + y_max = numpy.max(pts_vec[:, 1]) + z_min = numpy.min(pts_vec[:, 2]) + z_max = numpy.max(pts_vec[:, 2]) + + # Temporary ref axis nodes coordinates - aligned with main system of reference + x_nodes = xFraction * (x_max - x_min) + x_min # chordwise + y_nodes = y_max - yFraction * (y_max - y_min) # top-bottom + z_nodes = z_max - zFraction * (z_max - z_min) # top-bottom + + # These are the FFD ref axis nodes - if the block has not been rotated + nds = [x_nodes, y_nodes, z_nodes] + nds_final = numpy.copy(nds) + + if rotType == 0 and rot0ang: + # rotating the non-aligned FFDs back in position + nds_final[:] = geo_utils.rotVbyW(nds, rot0axis, numpy.pi / 180 * (-rot0ang)) + + # insert the final coordinates in the var to be passed to pySpline: + refaxisNodes[place+i,0] = nds_final[0] + refaxisNodes[place+i,1] = nds_final[1] + refaxisNodes[place+i,2] = nds_final[2] + place += i + 1 # Add additional volumes From 1e0ee664aacfa425a740a2a99944655eb6334230 Mon Sep 17 00:00:00 2001 From: Marco Mangano Date: Thu, 25 Feb 2021 11:42:33 +0100 Subject: [PATCH 08/18] added test for generalized xyz fraction --- tests/reg_tests/ref/test_DVGeometry_23.ref | 31 ++++++++++++++++++++++ tests/reg_tests/test_DVGeometry.py | 19 ++++++++++++- 2 files changed, 49 insertions(+), 1 deletion(-) create mode 100644 tests/reg_tests/ref/test_DVGeometry_23.ref diff --git a/tests/reg_tests/ref/test_DVGeometry_23.ref b/tests/reg_tests/ref/test_DVGeometry_23.ref new file mode 100644 index 00000000..b14c5430 --- /dev/null +++ b/tests/reg_tests/ref/test_DVGeometry_23.ref @@ -0,0 +1,31 @@ +{ + "RefAxis_nodes_coord": { + "__ndarray__": [ + [ + -0.4, + -0.09999999999999998, + 0.0 + ], + [ + -0.4, + -0.09999999999999998, + 3.32194917 + ], + [ + -0.4, + -0.09999999999999998, + 5.78384945 + ], + [ + -0.4, + -0.09999999999999998, + 8.0 + ] + ], + "dtype": "float64", + "shape": [ + 4, + 3 + ] + } +} \ No newline at end of file diff --git a/tests/reg_tests/test_DVGeometry.py b/tests/reg_tests/test_DVGeometry.py index f0f622fd..4c770735 100644 --- a/tests/reg_tests/test_DVGeometry.py +++ b/tests/reg_tests/test_DVGeometry.py @@ -805,7 +805,24 @@ def test_22(self, train=False, refDeriv=False): handler.par_add_norm('norm', norm_diff, rtol=1e-7, atol=1e-7) os.remove(copyName) - + def train_23_xyzFraction(self, train=True, refDeriv=True): + self.test_23_xyzFraction(train=train, refDeriv=refDeriv) + + def test_23_xyzFraction(self, train=False, refDeriv=False): + """ + Test 23 + """ + refFile = os.path.join(self.base_path,'ref/test_DVGeometry_23.ref') + with BaseRegTest(refFile, train=train) as handler: + handler.root_print("Test generalized axis node location section in plane") + DVGeo = DVGeometry(os.path.join(self.base_path,'../inputFiles/2x1x8_rectangle.xyz')) + xfraction = 0.3 + yfraction = 0.6 + rotType = 0 + DVGeo.addRefAxis("RefAx", xFraction=xfraction, yFraction=yfraction, alignIndex="k", rotType=rotType) + nodes_loc = DVGeo.axis['RefAx']['curve'].X + + handler.root_add_val("RefAxis_nodes_coord",nodes_loc,rtol=1e-12,atol=1e-12) if __name__ == '__main__': unittest.main() From f96758cb8226bed20f8eda4fb540598ee2d44a9f Mon Sep 17 00:00:00 2001 From: Marco Mangano Date: Thu, 25 Feb 2021 12:49:05 +0100 Subject: [PATCH 09/18] added functions to commonUtils --- tests/reg_tests/commonUtils.py | 35 +++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/tests/reg_tests/commonUtils.py b/tests/reg_tests/commonUtils.py index 21d77b4b..bb83380c 100644 --- a/tests/reg_tests/commonUtils.py +++ b/tests/reg_tests/commonUtils.py @@ -176,11 +176,17 @@ def totalSensitivityCS(DVGeo,nPt,ptName): return dIdxCS -def testSensitivities(DVGeo,refDeriv,handler): +def testSensitivities(DVGeo,refDeriv,handler,pointset=1): #create test points points = numpy.zeros([2,3]) - points[0,:] = [0.25,0,0] - points[1,:] = [-0.25,0,0] + if pointset == 1: + points[0,:] = [0.25,0,0] + points[1,:] = [-0.25,0,0] + elif pointset == 2: + points[0, :] = [0.25, 0.4, 4] + points[1, :] = [-0.8, 0.2, 7] + else: + raise Warning("Enter a valid pointset") # add points to the geometry object ptName = 'testPoints' @@ -235,3 +241,26 @@ def testSensitivitiesD8(DVGeo,refDeriv,handler): dIdx = DVGeo.totalSensitivity(dIdPt,ptName) handler.root_add_dict("dIdx",dIdx,rtol=1e-7,atol=1e-7) + +# --- Adding standard twist and single axis scaling functions --- +# These functions are added for Test 24 but could be extended to other tests + +fix_root_sect=1 +nRefAxPts = 4 + +def twist(val, geo): + axis_key = list(geo.axis.keys())[0] + for i in range(fix_root_sect, nRefAxPts): + geo.rot_theta[axis_key].coef[i] = val[i - fix_root_sect] + +def thickness(val, geo): + axis_key = list(geo.axis.keys())[0] + + for i in range(1, nRefAxPts): + geo.scale_z[axis_key].coef[i] = val[i - fix_root_sect] + +def chord(val, geo): + axis_key = list(geo.axis.keys())[0] + + for i in range(1, nRefAxPts): + geo.scale_x[axis_key].coef[i] = val[i - fix_root_sect] \ No newline at end of file From e375a8f29387c7537d40f92f8b37a94dc07647cf Mon Sep 17 00:00:00 2001 From: Marco Mangano Date: Thu, 25 Feb 2021 12:51:31 +0100 Subject: [PATCH 10/18] WIP: added test for non-aligned FFDs - FD-trained test is failing --- tests/reg_tests/ref/test_DVGeometry_24.ref | 290 +++++++++++++++++++++ tests/reg_tests/test_DVGeometry.py | 60 ++++- 2 files changed, 345 insertions(+), 5 deletions(-) create mode 100644 tests/reg_tests/ref/test_DVGeometry_24.ref diff --git a/tests/reg_tests/ref/test_DVGeometry_24.ref b/tests/reg_tests/ref/test_DVGeometry_24.ref new file mode 100644 index 00000000..4bbd63c6 --- /dev/null +++ b/tests/reg_tests/ref/test_DVGeometry_24.ref @@ -0,0 +1,290 @@ +{ + "Updated FFD coordinates": { + "__ndarray__": [ + [ + -1.0, + -0.5, + -2.804661220402718e-18 + ], + [ + 1.0, + -0.5, + -2.804661220402718e-18 + ], + [ + -1.0, + 0.5, + 2.804661220402718e-18 + ], + [ + 1.0, + 0.5, + 2.804661220402718e-18 + ], + [ + -1.9820508075688774, + 0.5669872981077806, + 8.0 + ], + [ + 1.4820508075688774, + -1.4330127018922192, + 8.0 + ], + [ + -1.4820508075688774, + 1.4330127018922192, + 8.0 + ], + [ + 1.9820508075688774, + -0.5669872981077806, + 8.0 + ], + [ + -0.33333333, + -0.5, + -2.804661220402718e-18 + ], + [ + 0.33333333, + -0.5, + -2.804661220402718e-18 + ], + [ + -0.33333333, + 0.5, + 2.804661220402718e-18 + ], + [ + 0.33333333, + 0.5, + 2.804661220402718e-18 + ], + [ + -0.827350263416123, + -0.09967937189221938, + 8.0 + ], + [ + 0.32735026341612306, + -0.7663460318922193, + 8.0 + ], + [ + -0.3273502634161231, + 0.7663460318922193, + 8.0 + ], + [ + 0.8273502634161229, + 0.09967937189221941, + 8.0 + ], + [ + -0.11602540378443882, + -1.799038105676658, + 3.32194917 + ], + [ + -1.0, + -0.5, + 5.78384945 + ], + [ + 1.6160254037844386, + -0.799038105676658, + 3.32194917 + ], + [ + 1.0, + -0.5, + 5.78384945 + ], + [ + -1.6160254037844386, + 0.799038105676658, + 3.32194917 + ], + [ + -1.0, + 0.5, + 5.78384945 + ], + [ + 0.11602540378443882, + 1.799038105676658, + 3.32194917 + ], + [ + 1.0, + 0.5, + 5.78384945 + ], + [ + 0.46132486829193836, + -1.465704770676658, + 3.32194917 + ], + [ + -0.33333333, + -0.5, + 5.78384945 + ], + [ + 1.0386751317080614, + -1.132371440676658, + 3.32194917 + ], + [ + 0.33333333, + -0.5, + 5.78384945 + ], + [ + -1.0386751317080614, + 1.132371440676658, + 3.32194917 + ], + [ + -0.33333333, + 0.5, + 5.78384945 + ], + [ + -0.46132486829193836, + 1.465704770676658, + 3.32194917 + ], + [ + 0.33333333, + 0.5, + 5.78384945 + ] + ], + "dtype": "float64", + "shape": [ + 32, + 3 + ] + }, + "dIdx": { + "chord": { + "__ndarray__": [ + [ + 0.1024175839015723, + 0.08303406057669105, + 0.02243968582087641 + ], + [ + 0.0, + 0.0, + 0.0 + ], + [ + 0.0, + 0.0, + 0.0 + ], + [ + -0.04462049891340136, + -0.25749326610198464, + -0.4953088356433655 + ], + [ + 0.0, + 0.0, + 0.0 + ], + [ + 0.0, + 0.0, + 0.0 + ] + ], + "dtype": "float64", + "shape": [ + 6, + 3 + ] + }, + "thickness": { + "__ndarray__": [ + [ + 0.0, + 0.0, + 0.0 + ], + [ + 0.16386813424251578, + 0.13285449692270523, + 0.03590349731340259 + ], + [ + 0.0, + 0.0, + 0.0 + ], + [ + 0.0, + 0.0, + 0.0 + ], + [ + 0.011155124728350618, + 0.06437331652549699, + 0.12382720891084109 + ], + [ + 0.0, + 0.0, + 0.0 + ] + ], + "dtype": "float64", + "shape": [ + 6, + 3 + ] + }, + "twist": { + "__ndarray__": [ + [ + -0.0028615969382142503, + -0.0023200119009064712, + -0.0006269756988333541 + ], + [ + 0.0017850272897235175, + 0.0014471935234128264, + 0.0003910993604533397 + ], + [ + 0.0, + 0.0, + 0.0 + ], + [ + -0.0001940139472467184, + -0.001119603907666633, + -0.0021536474187600074 + ], + [ + -0.0007789441267630481, + -0.004495083474986283, + -0.008646651603049227 + ], + [ + 0.0, + 0.0, + 0.0 + ] + ], + "dtype": "float64", + "shape": [ + 6, + 3 + ] + } + } +} \ No newline at end of file diff --git a/tests/reg_tests/test_DVGeometry.py b/tests/reg_tests/test_DVGeometry.py index 4c770735..1c7ca778 100644 --- a/tests/reg_tests/test_DVGeometry.py +++ b/tests/reg_tests/test_DVGeometry.py @@ -805,16 +805,16 @@ def test_22(self, train=False, refDeriv=False): handler.par_add_norm('norm', norm_diff, rtol=1e-7, atol=1e-7) os.remove(copyName) - def train_23_xyzFraction(self, train=True, refDeriv=True): - self.test_23_xyzFraction(train=train, refDeriv=refDeriv) + def train_23_xyzFraction(self, train=True): + self.test_23_xyzFraction(train=train) - def test_23_xyzFraction(self, train=False, refDeriv=False): + def test_23_xyzFraction(self, train=False): """ Test 23 """ refFile = os.path.join(self.base_path,'ref/test_DVGeometry_23.ref') with BaseRegTest(refFile, train=train) as handler: - handler.root_print("Test generalized axis node location section in plane") + handler.root_print("Test generalized axis node location section in plane") DVGeo = DVGeometry(os.path.join(self.base_path,'../inputFiles/2x1x8_rectangle.xyz')) xfraction = 0.3 yfraction = 0.6 @@ -822,7 +822,57 @@ def test_23_xyzFraction(self, train=False, refDeriv=False): DVGeo.addRefAxis("RefAx", xFraction=xfraction, yFraction=yfraction, alignIndex="k", rotType=rotType) nodes_loc = DVGeo.axis['RefAx']['curve'].X - handler.root_add_val("RefAxis_nodes_coord",nodes_loc,rtol=1e-12,atol=1e-12) + handler.root_add_val("RefAxis_nodes_coord",nodes_loc,rtol=1e-12,atol=1e-12) + + def train_24_rot0_nonaligned(self, train=True, refDeriv=True): + self.test_24_rot0_nonaligned(train=train, refDeriv=refDeriv) + + def test_24_rot0_nonaligned(self, train=False, refDeriv=False): + """ + Test 24 + """ + refFile = os.path.join(self.base_path,'ref/test_DVGeometry_24.ref') + with BaseRegTest(refFile, train=train) as handler: + handler.root_print("Test twist and scaling for FFDs non-aligned to main system of reference") + DVGeo = DVGeometry(os.path.join(self.base_path,'../inputFiles/2x1x8_rectangle.xyz')) + rotType = 0 + xfraction = 0.5 + nRefAxPts = DVGeo.addRefAxis("RefAx", xFraction=xfraction, alignIndex="k", rotType=rotType, rot0ang=-90) + + fix_root_sect = 1 + nTwist = nRefAxPts - fix_root_sect + + DVGeo.addGeoDVGlobal(dvName="twist", value=[0] * nTwist, func=commonUtils.twist, lower=-90, upper=90, scale=1) + DVGeo.addGeoDVGlobal(dvName="thickness", value=[1.0] * nTwist, func=commonUtils.thickness, lower=0.7, upper=5., scale=1) + DVGeo.addGeoDVGlobal(dvName="chord", value=[1.0] * nTwist, func=commonUtils.chord, lower=0.7, upper=5., scale=1) + + commonUtils.testSensitivities(DVGeo, refDeriv, handler, pointset=2) + + x = DVGeo.getValues() + + # Modifying the twist + keyName = "twist" + twistTest = [30, 0, -30] + x[keyName] = twistTest + + # Modifying the chord + keyName = "thickness" + thickTest = [3.0, 1.0, 1.0] + x[keyName] = thickTest + + # Modifying the chord + keyName = "chord" + chordTest = [1.0, 1.0, 2.0] + x[keyName] = chordTest + + DVGeo.setDesignVars(x) + + DVGeo.update('testPoints') + FFD_coords = DVGeo.FFD.coef.copy() + + handler.root_add_val("Updated FFD coordinates",FFD_coords,rtol=1e-12,atol=1e-12) + + if __name__ == '__main__': unittest.main() From ff2fa29e67fb03a3b8d1c44f867990350c1d1ffd Mon Sep 17 00:00:00 2001 From: Marco Mangano Date: Thu, 25 Feb 2021 15:40:18 +0100 Subject: [PATCH 11/18] updated test 24 ref --- tests/reg_tests/ref/test_DVGeometry_24.ref | 72 +++++++++++----------- tests/reg_tests/test_DVGeometry.py | 2 +- 2 files changed, 37 insertions(+), 37 deletions(-) diff --git a/tests/reg_tests/ref/test_DVGeometry_24.ref b/tests/reg_tests/ref/test_DVGeometry_24.ref index 4bbd63c6..6e42e75a 100644 --- a/tests/reg_tests/ref/test_DVGeometry_24.ref +++ b/tests/reg_tests/ref/test_DVGeometry_24.ref @@ -172,9 +172,9 @@ "chord": { "__ndarray__": [ [ - 0.1024175839015723, - 0.08303406057669105, - 0.02243968582087641 + 0.10241758390157193, + 0.0830340605766905, + 0.022439685820876205 ], [ 0.0, @@ -187,9 +187,9 @@ 0.0 ], [ - -0.04462049891340136, - -0.25749326610198464, - -0.4953088356433655 + -0.044620498913401405, + -0.25749326610198675, + -0.4953088356433645 ], [ 0.0, @@ -216,14 +216,14 @@ 0.0 ], [ - 0.16386813424251578, - 0.13285449692270523, - 0.03590349731340259 + 0.16386813424251517, + 0.13285449692270485, + 0.035903497313401936 ], [ - 0.0, - 0.0, - 0.0 + -1.003402930411725e-17, + -8.134991720436118e-18, + -2.198455153152664e-18 ], [ 0.0, @@ -231,14 +231,14 @@ 0.0 ], [ - 0.011155124728350618, - 0.06437331652549699, - 0.12382720891084109 + 0.011155124728350351, + 0.06437331652549669, + 0.12382720891084106 ], [ - 0.0, - 0.0, - 0.0 + -6.830543896331872e-19, + -3.9417288016724475e-18, + -7.582229752000605e-18 ] ], "dtype": "float64", @@ -250,34 +250,34 @@ "twist": { "__ndarray__": [ [ - -0.0028615969382142503, - -0.0023200119009064712, - -0.0006269756988333541 + -0.0028600384816319536, + -0.0023187483973818738, + -0.0006266342410998022 ], [ - 0.0017850272897235175, - 0.0014471935234128264, - 0.0003910993604533397 + 0.00178752405101997, + 0.0014492177483636706, + 0.00039164640068737623 ], [ - 0.0, - 0.0, - 0.0 + -2.88437708974355e-20, + -1.6137657620872173e-20, + -4.3611496822172335e-21 ], [ - -0.0001940139472467184, - -0.001119603907666633, - -0.0021536474187600074 + -0.00019469365498035163, + -0.0011235263237983936, + -0.0021611924990490384 ], [ - -0.0007789441267630481, - -0.004495083474986283, - -0.008646651603049227 + -0.0007787746199214066, + -0.0044941052951935736, + -0.008644769996196155 ], [ - 0.0, - 0.0, - 0.0 + 1.2566430479597225e-20, + 5.004377889235119e-20, + 9.626320031432152e-20 ] ], "dtype": "float64", diff --git a/tests/reg_tests/test_DVGeometry.py b/tests/reg_tests/test_DVGeometry.py index 1c7ca778..24cf648c 100644 --- a/tests/reg_tests/test_DVGeometry.py +++ b/tests/reg_tests/test_DVGeometry.py @@ -824,7 +824,7 @@ def test_23_xyzFraction(self, train=False): handler.root_add_val("RefAxis_nodes_coord",nodes_loc,rtol=1e-12,atol=1e-12) - def train_24_rot0_nonaligned(self, train=True, refDeriv=True): + def train_24_rot0_nonaligned(self, train=True, refDeriv=False): self.test_24_rot0_nonaligned(train=train, refDeriv=refDeriv) def test_24_rot0_nonaligned(self, train=False, refDeriv=False): From f063378ce64210c75a2930574a34e8027d8e86af Mon Sep 17 00:00:00 2001 From: Marco Mangano Date: Wed, 3 Mar 2021 12:10:13 +0100 Subject: [PATCH 12/18] added tests explanation --- tests/reg_tests/test_DVGeometry.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tests/reg_tests/test_DVGeometry.py b/tests/reg_tests/test_DVGeometry.py index 24cf648c..0a34a675 100644 --- a/tests/reg_tests/test_DVGeometry.py +++ b/tests/reg_tests/test_DVGeometry.py @@ -811,6 +811,11 @@ def train_23_xyzFraction(self, train=True): def test_23_xyzFraction(self, train=False): """ Test 23 + This test verifies the correct implementation of the generalized `xFraction`, `yFraction` (and indirectly `zFraction`) + Given an arbitrary input for the in-plane location of the reference axis nodes, the test sets up the axis object and compares the nodes location with a reference file. + As the geometry of the FFD box is simple, the values can be also hand calculated: + xFraction = 0.3, FFD x interval [-1,1] ---> 0.6 displacement from x min (% displ calculated from LE=xmin) --> x = -0.4 + yFraction = 0.6, FFD y interval [-0.5,0.5] ---> 0.6 displacement from y max (% displ calculated from top of the box=ymax) --> x = -0.1 """ refFile = os.path.join(self.base_path,'ref/test_DVGeometry_23.ref') with BaseRegTest(refFile, train=train) as handler: @@ -830,6 +835,14 @@ def train_24_rot0_nonaligned(self, train=True, refDeriv=False): def test_24_rot0_nonaligned(self, train=False, refDeriv=False): """ Test 24 + This test ensures that the scaling attributes (scale_x, scale_y, and scale_z) are effective when rotType=0 is selected. + Moreover, this test ensures that rotType=0 reference axis can handle (given appropriate input parameters) FFD blocks that are not aligned with the main system of reference, e.g. the blades of a 3-bladed wind turbine rotor. + The newly added input parameters rot0ang and rot0axis are used to provide the user control on this. + The operations that pyGeo performs for this test are the following: + We start from an initial "vertical" FFD box which, using the combination of rotType=0, rot0ang=-90, and rot0axis=[1,0,0] for addRefAxis(), is first rotated to have its "spanwise" axis along the y axis. + Then, the script scales the 2nd section along the z axis for a "thickness" increase and the 4th section along the x axis for "chord" increase, it adds a +/- 30 deg twist respectively, and finally rotates the deformed FFD back in the initial position. + The twist is added to ensure that the operation order is maintained, and the scaling preserves the orthogonality of the FFD in the section plane. + This is a particular case as the FFD box is already aligned with the main axis and we "flip" the y and z axes, but the same criteria can be applied to a general rotation. """ refFile = os.path.join(self.base_path,'ref/test_DVGeometry_24.ref') with BaseRegTest(refFile, train=train) as handler: From 94812eb49ee0e1abd65a10e4a596099bee1377d7 Mon Sep 17 00:00:00 2001 From: Marco Mangano Date: Wed, 3 Mar 2021 12:14:00 +0100 Subject: [PATCH 13/18] renamed vars to singular --- pygeo/DVGeometry.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/pygeo/DVGeometry.py b/pygeo/DVGeometry.py index 7aade080..5ca57e21 100644 --- a/pygeo/DVGeometry.py +++ b/pygeo/DVGeometry.py @@ -465,23 +465,23 @@ def addRefAxis(self, name, curve=None, xFraction=None, yFraction=None, zFraction z_min = numpy.min(pts_vec[:, 2]) z_max = numpy.max(pts_vec[:, 2]) - # Temporary ref axis nodes coordinates - aligned with main system of reference - x_nodes = xFraction * (x_max - x_min) + x_min # chordwise - y_nodes = y_max - yFraction * (y_max - y_min) # top-bottom - z_nodes = z_max - zFraction * (z_max - z_min) # top-bottom + # Temporary ref axis node coordinates - aligned with main system of reference + x_node = xFraction * (x_max - x_min) + x_min # chordwise + y_node = y_max - yFraction * (y_max - y_min) # top-bottom + z_node = z_max - zFraction * (z_max - z_min) # top-bottom - # These are the FFD ref axis nodes - if the block has not been rotated - nds = [x_nodes, y_nodes, z_nodes] - nds_final = numpy.copy(nds) + # This is the FFD ref axis node - if the block has not been rotated + nd = [x_node, y_node, z_node] + nd_final = numpy.copy(nd) if rotType == 0 and rot0ang: # rotating the non-aligned FFDs back in position - nds_final[:] = geo_utils.rotVbyW(nds, rot0axis, numpy.pi / 180 * (-rot0ang)) + nd_final[:] = geo_utils.rotVbyW(nd, rot0axis, numpy.pi / 180 * (-rot0ang)) # insert the final coordinates in the var to be passed to pySpline: - refaxisNodes[place+i,0] = nds_final[0] - refaxisNodes[place+i,1] = nds_final[1] - refaxisNodes[place+i,2] = nds_final[2] + refaxisNodes[place + i, 0] = nd_final[0] + refaxisNodes[place + i, 1] = nd_final[1] + refaxisNodes[place + i, 2] = nd_final[2] place += i + 1 From b2c4a8a34cb9be8a925e857433cdaffff8f9bfd5 Mon Sep 17 00:00:00 2001 From: Marco Mangano Date: Wed, 3 Mar 2021 12:43:09 +0100 Subject: [PATCH 14/18] cleaner coordinates array reshaping - thx Josh --- pygeo/DVGeometry.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/pygeo/DVGeometry.py b/pygeo/DVGeometry.py index 5ca57e21..aacf510a 100644 --- a/pygeo/DVGeometry.py +++ b/pygeo/DVGeometry.py @@ -445,9 +445,10 @@ def addRefAxis(self, name, curve=None, xFraction=None, yFraction=None, zFraction skip = 1 for i in range(nSections[j]): # getting all the section control points coordinates - pts_tens = self.FFD.coef[sectionArr[i + skip, :, :], :] # shape=(A,B,3) - # reshaping into vector to allow rotation (if needed) - pts_vec = numpy.copy(pts_tens.reshape(numpy.shape(pts_tens)[0] * numpy.shape(pts_tens)[1], 3)) # shape=(A*B,3) + pts_tens = self.FFD.coef[sectionArr[i + skip, :, :], :] # shape=(xAxisNodes,yAxisnodes,3) + + # reshaping into vector to allow rotation (if needed) - leveraging on pts_tens.shape[2]=3 (FFD cp coordinates) + pts_vec = numpy.copy(pts_tens.reshape(-1, 3)) # new shape=(xAxisNodes*yAxisnodes,3) if rotType == 0 and rot0ang: # rotating the FFD to be aligned with main axes From 0df4ddc744a22f802fa6201c32a68726d980a3f0 Mon Sep 17 00:00:00 2001 From: Marco Mangano Date: Wed, 3 Mar 2021 13:23:31 +0100 Subject: [PATCH 15/18] less intrusive xyz fraction behavior --- pygeo/DVGeometry.py | 38 +++++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/pygeo/DVGeometry.py b/pygeo/DVGeometry.py index aacf510a..40796bd9 100644 --- a/pygeo/DVGeometry.py +++ b/pygeo/DVGeometry.py @@ -378,12 +378,6 @@ def addRefAxis(self, name, curve=None, xFraction=None, yFraction=None, zFraction # - 'x' is streamwise direction # Default to "mean" ref axis location along non-user specified direction - if xFraction is None: - xFraction = 0.5 - if yFraction is None: - yFraction = 0.5 - if zFraction is None: - zFraction = 0.5 # This is the block direction along which the reference axis will lie # alignIndex = 'k' @@ -458,18 +452,28 @@ def addRefAxis(self, name, curve=None, xFraction=None, yFraction=None, zFraction p_rot = geo_utils.rotVbyW(p_, rot0axis, numpy.pi / 180 * (rot0ang)) pts_vec[ct_ , :] = p_rot - # getting the bounds of the FFD section - x_min = numpy.min(pts_vec[:, 0]) - x_max = numpy.max(pts_vec[:, 0]) - y_min = numpy.min(pts_vec[:, 1]) - y_max = numpy.max(pts_vec[:, 1]) - z_min = numpy.min(pts_vec[:, 2]) - z_max = numpy.max(pts_vec[:, 2]) - # Temporary ref axis node coordinates - aligned with main system of reference - x_node = xFraction * (x_max - x_min) + x_min # chordwise - y_node = y_max - yFraction * (y_max - y_min) # top-bottom - z_node = z_max - zFraction * (z_max - z_min) # top-bottom + if xFraction: + # getting the bounds of the FFD section + x_min = numpy.min(pts_vec[:, 0]) + x_max = numpy.max(pts_vec[:, 0]) + x_node = xFraction * (x_max - x_min) + x_min # chordwise + else: + x_node = numpy.mean(pts_vec[:, 0]) + + if yFraction: + y_min = numpy.min(pts_vec[:, 1]) + y_max = numpy.max(pts_vec[:, 1]) + y_node = y_max - yFraction * (y_max - y_min) # top-bottom + else: + y_node = numpy.mean(pts_vec[:, 1]) + + if zFraction: + z_min = numpy.min(pts_vec[:, 2]) + z_max = numpy.max(pts_vec[:, 2]) + z_node = z_max - zFraction * (z_max - z_min) # top-bottom + else: + z_node = numpy.mean(pts_vec[:, 2]) # This is the FFD ref axis node - if the block has not been rotated nd = [x_node, y_node, z_node] From 7fda92b3ca58474e1cd22fd6d10d1f98d4e2a7df Mon Sep 17 00:00:00 2001 From: Marco Mangano Date: Wed, 3 Mar 2021 14:57:26 +0100 Subject: [PATCH 16/18] bugfix on a check that did not make sense --- pygeo/DVGeometry.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pygeo/DVGeometry.py b/pygeo/DVGeometry.py index 40796bd9..13e51ef4 100644 --- a/pygeo/DVGeometry.py +++ b/pygeo/DVGeometry.py @@ -444,7 +444,7 @@ def addRefAxis(self, name, curve=None, xFraction=None, yFraction=None, zFraction # reshaping into vector to allow rotation (if needed) - leveraging on pts_tens.shape[2]=3 (FFD cp coordinates) pts_vec = numpy.copy(pts_tens.reshape(-1, 3)) # new shape=(xAxisNodes*yAxisnodes,3) - if rotType == 0 and rot0ang: + if rot0ang: # rotating the FFD to be aligned with main axes for ct_ in range(numpy.shape(pts_vec)[0]): # here we loop over the pts_vec, rotate them and insert them inplace in pts_vec again @@ -479,7 +479,7 @@ def addRefAxis(self, name, curve=None, xFraction=None, yFraction=None, zFraction nd = [x_node, y_node, z_node] nd_final = numpy.copy(nd) - if rotType == 0 and rot0ang: + if rot0ang: # rotating the non-aligned FFDs back in position nd_final[:] = geo_utils.rotVbyW(nd, rot0axis, numpy.pi / 180 * (-rot0ang)) From 991d5d72e81135fdaea52e77f7cb1ed42369cea3 Mon Sep 17 00:00:00 2001 From: Marco Mangano Date: Tue, 16 Mar 2021 11:37:08 +0100 Subject: [PATCH 17/18] updated ang checks --- pygeo/DVGeometry.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pygeo/DVGeometry.py b/pygeo/DVGeometry.py index 13e51ef4..acb686ad 100644 --- a/pygeo/DVGeometry.py +++ b/pygeo/DVGeometry.py @@ -1254,7 +1254,7 @@ def updateCalculations(self, new_pts, isComplex, config): ang = self.axis[self.curveIDNames[ipt]]['rot0ang'] ax_dir = self.axis[self.curveIDNames[ipt]]['rot0axis'] bp_ = numpy.copy(base_pt) # copy of original pointset - will not be rotated - if ang: + if isinstance(ang,(float, int)): ang *= numpy.pi/180 # conv to [rad] # Rotating the FFD according to inputs # The FFD points should now be aligned with the main system of reference @@ -1276,7 +1276,7 @@ def updateCalculations(self, new_pts, isComplex, config): else: new_pts[ipt] = numpy.real(bp_ + new_vec*scale) - if ang: + if isinstance(ang,(float, int)): # Rotating to be aligned with main sys ref nv_ = numpy.copy(new_vec) new_vec = geo_utils.rotVbyW(nv_, ax_dir, ang) @@ -1286,7 +1286,7 @@ def updateCalculations(self, new_pts, isComplex, config): new_vec[1] *= scale_y new_vec[2] *= scale_z - if ang: + if isinstance(ang,(float, int)): # Rotating back the scaled pointset to its original position nv_rot = numpy.copy(new_vec) # nv_rot is scaled and rotated new_vec = geo_utils.rotVbyW(nv_rot , ax_dir, -ang) @@ -1307,7 +1307,7 @@ def updateCalculations(self, new_pts, isComplex, config): self.curveIDNames[ipt]](self.links_s[ipt])) D = self.links_x[ipt] - if ang: + if isinstance(ang,(float, int)): raise Warning("if rot0ang != 0, use rotType=0. The derivatives with other rotations are slightly off") # rotate non-aligned FFDs D_ = numpy.copy(D) @@ -1343,7 +1343,7 @@ def updateCalculations(self, new_pts, isComplex, config): D[0] *= scale_x D[1] *= scale_y D[2] *= scale_z - if ang: + if isinstance(ang,(float, int)): # rotate non-aligned FFDs back to initial position D_ = numpy.copy(D) bp_rot = numpy.copy(base_pt) # here base_pt has been rotated From 71798d4a7332cfaaedcbf2acc2aefa16047b8931 Mon Sep 17 00:00:00 2001 From: Marco Mangano Date: Tue, 16 Mar 2021 11:49:49 +0100 Subject: [PATCH 18/18] limited rotation to rotType=0 only --- pygeo/DVGeometry.py | 23 ++++++----------------- 1 file changed, 6 insertions(+), 17 deletions(-) diff --git a/pygeo/DVGeometry.py b/pygeo/DVGeometry.py index acb686ad..b3a358b1 100644 --- a/pygeo/DVGeometry.py +++ b/pygeo/DVGeometry.py @@ -1253,12 +1253,6 @@ def updateCalculations(self, new_pts, isComplex, config): # Variables for rotType = 0 rotation + scaling ang = self.axis[self.curveIDNames[ipt]]['rot0ang'] ax_dir = self.axis[self.curveIDNames[ipt]]['rot0axis'] - bp_ = numpy.copy(base_pt) # copy of original pointset - will not be rotated - if isinstance(ang,(float, int)): - ang *= numpy.pi/180 # conv to [rad] - # Rotating the FFD according to inputs - # The FFD points should now be aligned with the main system of reference - base_pt = geo_utils.rotVbyW(bp_, ax_dir, ang) scale = self.scale[self.curveIDNames[ipt]](self.links_s[ipt]) scale_x = self.scale_x[self.curveIDNames[ipt]](self.links_s[ipt]) @@ -1267,6 +1261,12 @@ def updateCalculations(self, new_pts, isComplex, config): rotType = self.axis[self.curveIDNames[ipt]]['rotType'] if rotType == 0: + bp_ = numpy.copy(base_pt) # copy of original pointset - will not be rotated + if isinstance(ang,(float, int)): # rotation active only if a non-default value is provided + ang *= numpy.pi/180 # conv to [rad] + # Rotating the FFD according to inputs + # The FFD points should now be aligned with the main system of reference + base_pt = geo_utils.rotVbyW(bp_, ax_dir, ang) deriv = self.refAxis.curves[ self.curveIDs[ipt]].getDerivative(self.links_s[ipt]) deriv /= geo_utils.euclideanNorm(deriv) # Normalize @@ -1307,11 +1307,6 @@ def updateCalculations(self, new_pts, isComplex, config): self.curveIDNames[ipt]](self.links_s[ipt])) D = self.links_x[ipt] - if isinstance(ang,(float, int)): - raise Warning("if rot0ang != 0, use rotType=0. The derivatives with other rotations are slightly off") - # rotate non-aligned FFDs - D_ = numpy.copy(D) - D = geo_utils.rotVbyW(D_, ax_dir, ang) rotM = self._getRotMatrix(rotX, rotY, rotZ, rotType) @@ -1343,12 +1338,6 @@ def updateCalculations(self, new_pts, isComplex, config): D[0] *= scale_x D[1] *= scale_y D[2] *= scale_z - if isinstance(ang,(float, int)): - # rotate non-aligned FFDs back to initial position - D_ = numpy.copy(D) - bp_rot = numpy.copy(base_pt) # here base_pt has been rotated - D = geo_utils.rotVbyW(D_ , ax_dir, -ang) - base_pt = geo_utils.rotVbyW(bp_rot, ax_dir, -ang) if isComplex: new_pts[ipt] = base_pt + D*scale