001/** 002 * CSTClassFunction -- A generic CST Class Function implementation. 003 * 004 * Copyright (C) 2014-2015, by Joseph A. Huwaldt. All rights reserved. 005 * 006 * This library is free software; you can redistribute it and/or modify it under the terms 007 * of the GNU Lesser General Public License as published by the Free Software Foundation; 008 * either version 2.1 of the License, or (at your option) any later version. 009 * 010 * This library is distributed in the hope that it will be useful, but WITHOUT ANY 011 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 012 * PARTICULAR PURPOSE. See the GNU Library General Public License for more details. 013 * 014 * You should have received a copy of the GNU Lesser General Public License along with 015 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - 016 * Suite 330, Boston, MA 02111-1307, USA. Or visit: http://www.gnu.org/licenses/lgpl.html 017 */ 018package geomss.geom.cst; 019 020import jahuwaldt.tools.math.MathTools; 021import static java.lang.Math.*; 022import javolution.context.ImmortalContext; 023import javolution.context.ObjectFactory; 024import javolution.lang.ValueType; 025import javolution.xml.XMLFormat; 026import javolution.xml.XMLSerializable; 027import javolution.xml.stream.XMLStreamException; 028import org.apache.commons.math3.analysis.differentiation.DerivativeStructure; 029 030/** 031 * A generic Class-Shape-Transform (CST) class function implementation. The "class" of the 032 * function is determined by the input exponents: C(s) = (s)^N1*(1 - s)^N2. 033 * 034 * <p> Modified by: Joseph A. Huwaldt </p> 035 * 036 * @author Joseph A. Huwaldt Date: March 14, 2014 037 * @version November 28, 2015 038 */ 039@SuppressWarnings({"serial", "CloneableImplementsClone"}) 040public final class CSTClassFunction implements Cloneable, XMLSerializable, ValueType { 041 // Reference: Kulfan, B.M., Bussoletti, J.E., "'Fundamental' Parametric Geometry 042 // Representations for Aircraft Component Shapes", AIAA-2006-6948. 043 044 // The exponents for the class function. 045 private double N1, N2; 046 047 /////////////////////// 048 // Factory creation. // 049 /////////////////////// 050 private CSTClassFunction() { } 051 052 @SuppressWarnings("unchecked") 053 private static final ObjectFactory<CSTClassFunction> FACTORY = new ObjectFactory<CSTClassFunction>() { 054 @Override 055 protected CSTClassFunction create() { 056 return new CSTClassFunction(); 057 } 058 }; 059 060 @SuppressWarnings("unchecked") 061 private static CSTClassFunction copyOf(CSTClassFunction original) { 062 CSTClassFunction obj = FACTORY.object(); 063 obj.N1 = original.N1; 064 obj.N2 = original.N2; 065 return obj; 066 } 067 068 /** 069 * Construct a new CST Class Function using the specified exponents. 070 * 071 * @param N1 The 1st exponent of the class function (leading edge exponent). 072 * @param N2 The 2nd exponent of the class function (trailing edge exponent). 073 * @return 074 */ 075 public static CSTClassFunction newInstance(double N1, double N2) { 076 CSTClassFunction obj = FACTORY.object(); 077 obj.N1 = N1; 078 obj.N2 = N2; 079 return obj; 080 } 081 082 /** 083 * A class function for a blunt-nosed airfoil (subsonic airfoil). 084 */ 085 public static final CSTClassFunction BLUNTNOSED_AIRFOIL; 086 087 /** 088 * A class function for a sharp-nosed airfoil (supersonic airfoil). 089 */ 090 public static final CSTClassFunction SHARPNOSED_AIRFOIL; 091 092 /** 093 * A class function for an elliptical shape/airfoil. 094 */ 095 public static final CSTClassFunction ELLIPTICAL; 096 097 /** 098 * A class function for a Sears-Haack minimum wave-drag body profile. 099 */ 100 public static final CSTClassFunction SEARS_HAACK; 101 102 /** 103 * A class function for a cone or wedge shape. 104 */ 105 public static final CSTClassFunction CONE_WEDGE; 106 107 /** 108 * A class function for a rectangular shape. 109 */ 110 public static final CSTClassFunction RECTANGULAR; 111 112 static { 113 ImmortalContext.enter(); 114 try { 115 BLUNTNOSED_AIRFOIL = CSTClassFunction.newInstance(0.5, 1.0); 116 SHARPNOSED_AIRFOIL = CSTClassFunction.newInstance(1.0, 1.0); 117 ELLIPTICAL = CSTClassFunction.newInstance(0.5,0.5); 118 SEARS_HAACK = CSTClassFunction.newInstance(0.75, 0.75); 119 CONE_WEDGE = CSTClassFunction.newInstance(1.0, 0.0); 120 RECTANGULAR = CSTClassFunction.newInstance(0.0, 0.0); 121 } finally { 122 ImmortalContext.exit(); 123 } 124 } 125 126 /** 127 * Return the first exponent of the class function, N1. 128 * 129 * @return The first exponent of the class function. 130 */ 131 public double getN1() { 132 return N1; 133 } 134 135 /** 136 * Return the second exponent of the class function, N2. 137 * 138 * @return The second exponent of the class function. 139 */ 140 public double getN2() { 141 return N2; 142 } 143 144 /** 145 * Return the value of this class function at the specified parametric location. 146 * 147 * @param s The parametric distance to calculate this class functions value for (0 to 148 * 1 inclusive). 149 * @return The value of this class function at the specified parametric location. 150 */ 151 public double getValue(double s) { 152 double t1; 153 if (MathTools.isApproxEqual(N1, 1.0)) // N1 == 1.0 154 t1 = s; 155 else if (MathTools.isApproxEqual(N1, 0.5)) // N1 == 0.5 156 t1 = sqrt(s); 157 else 158 t1 = pow(s, N1); 159 double t2 = 1 - s; 160 if (MathTools.isApproxEqual(N2, 0.5)) // N2 == 0.5 161 t2 = sqrt(t2); 162 else if (!MathTools.isApproxEqual(N2, 1.0)) // N2 != 1.0 163 t2 = pow(t2, N2); 164 return t1 * t2; 165 } 166 167 /** 168 * Calculate all the derivatives from <code>0</code> to <code>grade</code> with 169 * respect to parametric distance on the class function for the given parametric 170 * distance along the class function, <code>d^{grade}p(s)/d^{grade}s</code>. 171 * <p> 172 * Example:<br> 173 * 1st derivative (grade = 1), this returns <code>[p(s), dp(s)/ds]</code>;<br> 174 * 2nd derivative (grade = 2), this returns <code>[p(s), dp(s)/ds, d^2p(s)/d^2s]</code>; etc. 175 * </p> 176 * 177 * @param s Parametric distance to calculate derivatives for (0.0 to 1.0 178 * inclusive). 179 * @param grade The maximum grade to calculate the derivatives for (0 = value only, 180 * 1=value + 1st derivative, 2=value + 1st derivative + 2nd derivative, etc) 181 * @return A list of derivatives up to the specified grade of the class function at 182 * the specified parametric position. 183 * @throws IllegalArgumentException if the grade is < 0. 184 */ 185 public double[] getDerivatives(double s, int grade) { 186 // This works around a problem in DerivativeStructure at s=0 and s=1. 187 if (s < MathTools.EPS) 188 s = MathTools.EPS; 189 else if (s > 1 - MathTools.EPS) 190 s = 1 - MathTools.EPS; 191 192 // Construct the class function equation. 193 DerivativeStructure x = new DerivativeStructure(1, grade, 0, s); // f(x) = x 194 DerivativeStructure xN1 = x.pow(N1); // x^N1 195 DerivativeStructure OmxN2 = x.negate().add(1).pow(N2); // (1 - x)^N2 196 DerivativeStructure Cf = xN1.multiply(OmxN2); // Cf(x) = (x)^N1*(1-x)^N2 197 198 // Return the derivatives. 199 double[] ders = Cf.getAllDerivatives(); 200 201 return ders; 202 } 203 204 /** 205 * Compares this CSTClassFunction against the specified object for strict equality 206 * (same values). 207 * 208 * @param obj the object to compare with. 209 * @return <code>true</code> if this object is identical to that object; 210 * <code>false</code> otherwise. 211 */ 212 @Override 213 public boolean equals(Object obj) { 214 if (this == obj) 215 return true; 216 if ((obj == null) || (obj.getClass() != this.getClass())) 217 return false; 218 219 CSTClassFunction that = (CSTClassFunction)obj; 220 return this.N1 == that.N1 && this.N2 == that.N2; 221 } 222 223 /** 224 * Returns the hash code for this object. 225 * 226 * @return the hash code value. 227 */ 228 @Override 229 public int hashCode() { 230 int hash = 7; 231 hash = hash * 31 + makeVarCode(N1); 232 hash = hash * 31 + makeVarCode(N2); 233 return hash; 234 } 235 236 private static int makeVarCode(double value) { 237 long bits = Double.doubleToLongBits(value); 238 int var_code = (int)(bits ^ (bits >>> 32)); 239 return var_code; 240 } 241 242 /** 243 * Returns a copy of this CSTClassFunction instance 244 * {@link javolution.context.AllocatorContext allocated} by the calling thread 245 * (possibly on the stack). 246 * 247 * @return an identical and independent copy of this object. 248 */ 249 @Override 250 public CSTClassFunction copy() { 251 return copyOf(this); 252 } 253 254 /** 255 * Holds the default XML representation for this object. 256 */ 257 protected static final XMLFormat<CSTClassFunction> XML = new XMLFormat<CSTClassFunction>(CSTClassFunction.class) { 258 259 @Override 260 public CSTClassFunction newInstance(Class<CSTClassFunction> cls, XMLFormat.InputElement xml) throws XMLStreamException { 261 return FACTORY.object(); 262 } 263 264 @Override 265 public void read(XMLFormat.InputElement xml, CSTClassFunction obj) throws XMLStreamException { 266 double N1 = xml.getAttribute("N1", 1.0); 267 double N2 = xml.getAttribute("N2", 1.0); 268 obj.N1 = N1; 269 obj.N2 = N2; 270 } 271 272 @Override 273 public void write(CSTClassFunction obj, XMLFormat.OutputElement xml) throws XMLStreamException { 274 xml.setAttribute("N1", obj.N1); 275 xml.setAttribute("N2", obj.N2); 276 } 277 }; 278 279}