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 &lt; 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}