1 /*  _______________________________________________________________________
2 
3     PECOS: Parallel Environment for Creation Of Stochastics
4     Copyright (c) 2011, Sandia National Laboratories.
5     This software is distributed under the GNU Lesser General Public License.
6     For more information, see the README file in the top Pecos directory.
7     _______________________________________________________________________ */
8 
9 //- Class:       DiscrepancyCalculator
10 //- Description: Implementation code for the DiscrepancyCalculator class
11 //- Owner:       Mike Eldred
12 //- Checked by:
13 
14 #include "DiscrepancyCalculator.hpp"
15 #include "SurrogateData.hpp"
16 
17 static const char rcsId[]="@(#) $Id: DiscrepancyCalculator.cpp 7024 2010-10-16 01:24:42Z mseldre $";
18 
19 
20 namespace Pecos {
21 
22 bool DiscrepancyCalculator::
check_multiplicative(Real truth_fn,Real approx_fn,short corr_order)23 check_multiplicative(Real truth_fn, Real approx_fn, short corr_order)
24 {
25   // Multiplicative will fail if response functions are near zero.
26   //   0th order:     a truth_val == 0 causes a zero scaling which will cause
27   //                  optimization failure; an approx_val == 0 will cause a
28   //                  division by zero FPE.
29   //   1st/2nd order: a truth_val == 0 is OK (so long as the total scaling
30   //                  function != 0); an approx_val == 0 will cause a division
31   //                  by zero FPE.
32   return
33     ( std::fabs(approx_fn) < Pecos::SMALL_NUMBER ||
34       ( corr_order == 0 && std::fabs(truth_fn) < Pecos::SMALL_NUMBER ) );
35 }
36 
37 
38 bool DiscrepancyCalculator::
check_multiplicative(const RealVector & truth_fns,const RealVector & approx_fns,short corr_order)39 check_multiplicative(const RealVector& truth_fns, const RealVector& approx_fns,
40 		     short corr_order)
41 {
42   bool bad_scaling = false;
43   size_t i, num_fns = std::min(truth_fns.length(), approx_fns.length());
44   for (i=0; i<num_fns; ++i)
45     if ( std::fabs(approx_fns[i]) < Pecos::SMALL_NUMBER ||
46 	 ( corr_order == 0 && std::fabs(truth_fns[i]) < Pecos::SMALL_NUMBER ) )
47       { bad_scaling = true; break; }
48 
49   return bad_scaling;
50 }
51 
52 
53 void DiscrepancyCalculator::
compute_additive(Real truth_fn,Real approx_fn,Real & discrep_fn)54 compute_additive(Real truth_fn, Real approx_fn, Real& discrep_fn)
55 {
56   // -----------------------------
57   // Additive 0th order correction
58   // -----------------------------
59   discrep_fn = truth_fn - approx_fn;
60 }
61 
62 
63 void DiscrepancyCalculator::
compute_additive(const RealVector & truth_grad,const RealVector & approx_grad,RealVector & discrep_grad)64 compute_additive(const RealVector& truth_grad, const RealVector& approx_grad,
65 		 RealVector& discrep_grad)
66 {
67   // -----------------------------
68   // Additive 1st order correction
69   // -----------------------------
70   size_t v, num_v = std::min(truth_grad.length(), approx_grad.length());
71   if (discrep_grad.length() != num_v) discrep_grad.sizeUninitialized(num_v);
72   for (v=0; v<num_v; ++v)
73     discrep_grad[v] = truth_grad[v] - approx_grad[v];
74 }
75 
76 
77 void DiscrepancyCalculator::
compute_additive(const RealSymMatrix & truth_hess,const RealSymMatrix & approx_hess,RealSymMatrix & discrep_hess)78 compute_additive(const RealSymMatrix& truth_hess,
79 		 const RealSymMatrix& approx_hess, RealSymMatrix& discrep_hess)
80 {
81   // -----------------------------
82   // Additive 2nd order correction
83   // -----------------------------
84   size_t r, c, num_v = std::min(truth_hess.numRows(), approx_hess.numRows());
85   if (discrep_hess.numRows() != num_v)
86     discrep_hess.shapeUninitialized(num_v);
87   for (r=0; r<num_v; ++r)
88     for (c=0; c<=r; ++c) // lower half
89       discrep_hess(r,c) = truth_hess(r,c) - approx_hess(r,c);
90 }
91 
92 
93 void DiscrepancyCalculator::
compute_multiplicative(Real truth_fn,Real approx_fn,Real & discrep_fn)94 compute_multiplicative(Real truth_fn, Real approx_fn, Real& discrep_fn)
95 {
96   // -----------------------------------
97   // Multiplicative 0th order correction
98   // -----------------------------------
99   discrep_fn = truth_fn / approx_fn;
100 }
101 
102 
103 void DiscrepancyCalculator::
compute_multiplicative(Real truth_fn,const RealVector & truth_grad,Real approx_fn,const RealVector & approx_grad,RealVector & discrep_grad)104 compute_multiplicative(Real truth_fn, const RealVector& truth_grad,
105 		       Real approx_fn, const RealVector& approx_grad,
106 		       RealVector& discrep_grad)
107 {
108   // -----------------------------------
109   // Multiplicative 1st order correction
110   // -----------------------------------
111   // The beta-correction method is based on the work of Chang and Haftka,
112   // and Alexandrov.  It is a multiplicative correction like the "scaled"
113   // correction method, but it uses gradient information to achieve
114   // 1st-order consistency (matches the high-fidelity function values and
115   // the high-fidelity gradients at the center of the approximation region).
116   size_t v, num_v = std::min(truth_grad.length(), approx_grad.length());
117   if (discrep_grad.length() != num_v) discrep_grad.sizeUninitialized(num_v);
118   Real ratio = truth_fn / approx_fn;
119   for (v=0; v<num_v; ++v)
120     discrep_grad[v] = (truth_grad[v] - approx_grad[v] * ratio) / approx_fn;
121 }
122 
123 
124 void DiscrepancyCalculator::
compute_multiplicative(Real truth_fn,const RealVector & truth_grad,const RealSymMatrix & truth_hess,Real approx_fn,const RealVector & approx_grad,const RealSymMatrix & approx_hess,RealSymMatrix & discrep_hess)125 compute_multiplicative(Real truth_fn, const RealVector& truth_grad,
126 		       const RealSymMatrix& truth_hess,
127 		       Real approx_fn, const RealVector& approx_grad,
128 		       const RealSymMatrix& approx_hess,
129 		       RealSymMatrix& discrep_hess)
130 {
131   // -----------------------------------
132   // Multiplicative 2nd order correction
133   // -----------------------------------
134   size_t r, c, num_v = std::min(truth_hess.numRows(), approx_hess.numRows());
135   if (discrep_hess.numRows() != num_v)
136     discrep_hess.shapeUninitialized(num_v);
137   // consider use of Teuchos assign and operator-=
138   Real ratio2 = 2. * truth_fn / approx_fn, approx_sq = approx_fn * approx_fn;
139   for (r=0; r<num_v; ++r)
140     for (c=0; c<=r; ++c) // lower half
141       discrep_hess(r,c) = ( truth_hess(r,c) * approx_fn - approx_hess(r,c) *
142 	truth_fn + ratio2 * approx_grad[r] * approx_grad[c] - truth_grad[r] *
143 	approx_grad[c] - approx_grad[r] * truth_grad[c] ) / approx_sq;
144 }
145 
146 
147 void DiscrepancyCalculator::
compute(const SDRArray & hf_sdr_array,const SDRArray & lf_sdr_array,SDRArray & delta_sdr_array,short combine_type)148 compute(const SDRArray& hf_sdr_array, const SDRArray& lf_sdr_array,
149 	SDRArray& delta_sdr_array, short combine_type)
150 {
151   size_t i, num_pts = std::min(hf_sdr_array.size(), lf_sdr_array.size());
152 
153   // Note: SurrogateData::size_active_sdr() is used to allocate delta_sdr_array
154 
155   switch (combine_type) {
156   case MULT_COMBINE:
157     for (i=0; i<num_pts; ++i) {
158       const SurrogateDataResp& lf_sdr  =    lf_sdr_array[i];
159       const SurrogateDataResp& hf_sdr  =    hf_sdr_array[i];
160       SurrogateDataResp&    delta_sdr  = delta_sdr_array[i];
161       short                 delta_bits = delta_sdr.active_bits();
162       short                 corr_order = (delta_bits & 2) ? 1 : 0;
163       if (check_multiplicative(hf_sdr.response_function(),
164 			       lf_sdr.response_function(), corr_order)) {
165 	PCerr << "Error: numerical FPE in computing multiplicative discrepancy."
166 	      << "\n       Please change to additive discrepancy." << std::endl;
167 	abort_handler(-1);
168       }
169       if (delta_bits & 1)
170 	compute_multiplicative(hf_sdr.response_function(),
171 			       lf_sdr.response_function(),
172 			       delta_sdr.response_function_view());
173       if (delta_bits & 2) {
174 	RealVector delta_grad(delta_sdr.response_gradient_view());
175 	compute_multiplicative(hf_sdr.response_function(),
176 			       hf_sdr.response_gradient(),
177 			       lf_sdr.response_function(),
178 			       lf_sdr.response_gradient(), delta_grad);
179       }
180       if (delta_bits & 4) {
181 	RealSymMatrix delta_hess(delta_sdr.response_hessian_view());
182 	compute_multiplicative(hf_sdr.response_function(),
183 			       hf_sdr.response_gradient(),
184 			       hf_sdr.response_hessian(),
185 			       lf_sdr.response_function(),
186 			       lf_sdr.response_gradient(),
187 			       lf_sdr.response_hessian(), delta_hess);
188       }
189     }
190     break;
191   default: //case ADD_COMBINE: (correction specification not required)
192     for (i=0; i<num_pts; ++i) {
193       const SurrogateDataResp& lf_sdr  =    lf_sdr_array[i];
194       const SurrogateDataResp& hf_sdr  =    hf_sdr_array[i];
195       SurrogateDataResp&    delta_sdr  = delta_sdr_array[i];
196       short                 delta_bits = delta_sdr.active_bits();
197       if (delta_bits & 1)
198 	compute_additive(hf_sdr.response_function(), lf_sdr.response_function(),
199 			 delta_sdr.response_function_view());
200       if (delta_bits & 2) {
201 	RealVector delta_grad(delta_sdr.response_gradient_view());
202 	compute_additive(hf_sdr.response_gradient(), lf_sdr.response_gradient(),
203 			 delta_grad);
204       }
205       if (delta_bits & 4) {
206 	RealSymMatrix delta_hess(delta_sdr.response_hessian_view());
207 	compute_additive(hf_sdr.response_hessian(), lf_sdr.response_hessian(),
208 			 delta_hess);
209       }
210     }
211     break;
212   }
213 }
214 
215 
216 void DiscrepancyCalculator::
compute(SurrogateData & surr_data,const UShortArray & delta_key,short combine_type)217 compute(SurrogateData& surr_data, const UShortArray& delta_key,
218 	short combine_type)
219 {
220   UShortArray hf_key, lf_key;  extract_keys(delta_key, hf_key, lf_key);
221 
222   const std::map<UShortArray, SDRArray>& resp_map
223     = surr_data.response_data_map();
224   std::map<UShortArray, SDRArray>::const_iterator
225     lf_cit = resp_map.find(lf_key), hf_cit = resp_map.find(hf_key);
226   if (lf_cit == resp_map.end() || hf_cit == resp_map.end()) {
227     PCerr << "Error: key lookup failure for individual fidelity in Discrepancy"
228 	  << "Calculator::compute()" << std::endl;
229     abort_handler(-1);
230   }
231 
232   surr_data.active_key(delta_key);
233   surr_data.variables_data(surr_data.variables_data(hf_key)); // shallow copies
234   surr_data.anchor_index(surr_data.anchor_index(hf_key));
235   surr_data.pop_count_stack(surr_data.pop_count_stack(hf_key));
236 
237   // TO DO: do this more incrementally (based on curr state of delta sdr_array)
238   const SDRArray& hf_sdr_array = hf_cit->second;
239   surr_data.size_active_sdr(hf_sdr_array);
240   compute(hf_sdr_array, lf_cit->second, surr_data.response_data(),combine_type);
241 
242   // compute discrepancy faults from scratch (aggregates LF,HF failures)
243   surr_data.data_checks();
244 }
245 
246 } // namespace Pecos
247