CompositeFunction.cpp 20.7 KB
Newer Older
1
2
3
4
//----------------------------------------------------------------------
// Includes
//----------------------------------------------------------------------
#include "MantidKernel/Exception.h"
5
6
#include "MantidAPI/CompositeFunction.h"
#include "MantidAPI/ParameterTie.h"
7
#include "MantidAPI/IConstraint.h"
8
#include "MantidAPI/FunctionFactory.h"
9

10
#include <boost/lexical_cast.hpp>
11
12
13
#include <boost/shared_array.hpp>
#include <sstream>
#include <iostream>
14
#include <algorithm>
15
16
17
18
19
20

namespace Mantid
{
namespace API
{

Peterson, Peter's avatar
Peterson, Peter committed
21
22
using std::size_t;

23
DECLARE_FUNCTION(CompositeFunction)
24

25
26
27
28
29
30
31
32
33
34
///Destructor
CompositeFunction::~CompositeFunction()
{
}

/// Function initialization. Declare function parameters in this method.
void CompositeFunction::init()
{
}

35
36
37
38
39
40
41
42
43
44
45
/** 
 * Writes itself into a string. Functions derived from CompositeFunction must
 * override this method with something like this:
 *   std::string NewFunction::asString()const
 *   {
 *      ostr << "composite=" << this->name() << ';';
 *      // write NewFunction's own attributes and parameters
 *      ostr << CompositeFunction::asString();
 *      // write NewFunction's own ties and constraints
 *      // ostr << ";constraints=(" << ... <<")";
 *   }
46
 * @return the string representation of the composite function
47
 */
48
49
50
std::string CompositeFunction::asString()const
{
  std::ostringstream ostr;
51
52
53
54
55
56
57
  
  // if empty just return function name
  if (nFunctions() == 0)
  {
    return "name=" + name();
  }

58
  if (name() != "CompositeFunction")
59
60
61
  {
    ostr << "composite=" <<name() << ";";
  }
Peterson, Peter's avatar
Peterson, Peter committed
62
  for(size_t i=0;i<nFunctions();i++)
63
  {
64
65
    IFunction_sptr fun = getFunction(i);
    bool isComp = boost::dynamic_pointer_cast<CompositeFunction>(fun) != 0;
66
    if (isComp) ostr << '(';
67
    ostr << fun->asString();
68
    if (isComp) ostr << ')';
69
70
71
72
73
74
    if (i < nFunctions() - 1)
    {
      ostr << ';';
    }
  }
  std::string ties;
75
  for(size_t i=0;i<nParams();i++)
76
77
78
79
  {
    const ParameterTie* tie = getTie(i);
    if (tie)
    {
80
81
      IFunction_sptr fun = getFunction(functionIndex(i));
      std::string tmp = tie->asString(fun.get());
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
      if (tmp.empty())
      {
        tmp = tie->asString(this);
        if (!tmp.empty())
        {
          if (!ties.empty())
          {
            ties += ",";
          }
          ties += tmp;
        }
      }
    }
  }
  if (!ties.empty())
  {
    ostr << ";ties=(" << ties << ")";
99
100
101
102
  }
  return ostr.str();
}

103
104
105
106
107
108
/** Function you want to fit to. 
 *  @param domain :: The buffer for writing the calculated values. Must be big enough to accept dataSize() values
 */
void CompositeFunction::function(const FunctionDomain& domain, FunctionValues& values)const
{
  FunctionValues tmp(domain);
109
  values.zeroCalculated();
110
111
112
113
114
115
116
117
118
119
120
121
122
123
  for(size_t iFun = 0; iFun < nFunctions(); ++iFun)
  {
    m_functions[ iFun ]->function(domain,tmp);
    values += tmp;
  }
}

/**
 * Derivatives of function with respect to active parameters
 * @param domain :: Function domain to get the arguments from.
 * @param jacobian :: A Jacobian to store the derivatives.
 */
void CompositeFunction::functionDeriv(const FunctionDomain& domain, Jacobian& jacobian)
{
124
125
126
127
128
  if ( m_useNumericDerivatives )
  {
    calNumericalDeriv(domain, jacobian);
  }
  else
129
  {
130
131
132
133
134
    for(size_t iFun = 0; iFun < nFunctions(); ++iFun)
    {
      PartialJacobian J(&jacobian,paramOffset(iFun));
      getFunction(iFun)->functionDeriv(domain,J);
    }
135
136
137
  }
}

138
/** Sets a new value to the i-th parameter.
139
140
141
 *  @param i :: The parameter index
 *  @param value :: The new value
 *  @param explicitlySet :: A boolean falgging the parameter as explicitly set (by user)
142
 */
143
void CompositeFunction::setParameter(size_t i, const double& value, bool explicitlySet)
144
{
145
  size_t iFun = functionIndex(i);
146
  m_functions[ iFun ]->setParameter(i - m_paramOffsets[iFun],value,explicitlySet);
147
148
}

149
150
151
152
153
154
/** Sets a new description to the i-th parameter.
 *  @param i :: The parameter index
 *  @param description :: The new description
 */
void CompositeFunction::setParameterDescription(size_t i, const std::string& description)
{
155
  size_t iFun = functionIndex(i);
156
157
158
  m_functions[ iFun ]->setParameterDescription(i - m_paramOffsets[iFun],description);
}

159
/** Get the i-th parameter.
160
 *  @param i :: The parameter index
161
 *  @return value of the requested parameter
162
 */
163
double CompositeFunction::getParameter(size_t i)const
164
{
Peterson, Peter's avatar
Peterson, Peter committed
165
  size_t iFun = functionIndex(i);
166
  return m_functions[ iFun ]->getParameter(i - m_paramOffsets[iFun]);
167
168
}

169
170
/**
 * Sets a new value to a parameter by name.
171
172
173
 * @param name :: The name of the parameter.
 * @param value :: The new value
 * @param explicitlySet :: A boolean falgging the parameter as explicitly set (by user)
174
175
 */
void CompositeFunction::setParameter(const std::string& name, const double& value, bool explicitlySet)
176
{
177
  std::string pname;
178
  size_t index;
179
  parseName(name,index,pname);
180
  getFunction(index)->setParameter(pname,value,explicitlySet);
181
182
}

183
184
185
/**
 * Sets a new description to a parameter by name.
 * @param name :: The name of the parameter.
186
 * @param description :: The new description
187
188
189
190
 */
void CompositeFunction::setParameterDescription(const std::string& name, const std::string& description)
{
  std::string pname;
191
  size_t index;
192
  parseName(name,index,pname);
193
  getFunction(index)->setParameterDescription(pname,description);
194
195
}

196
197
/**
 * Parameters by name.
198
 * @param name :: The name of the parameter.
199
 * @return value of the requested named parameter
200
 */
201
202
double CompositeFunction::getParameter(const std::string& name)const
{
203
  std::string pname;
204
  size_t index;
205
  parseName(name,index,pname);
206
  return getFunction(index)->getParameter(pname);
207
208
209
}

/// Total number of parameters
210
size_t CompositeFunction::nParams()const
211
212
213
214
{
  return m_nParams;
}

215
/**
216
 * 
217
 * @param name :: The name of a parameter
218
 * @return index of the requested named parameter
219
 */
220
size_t CompositeFunction::parameterIndex(const std::string& name)const
221
{
222
  std::string pname;
223
  size_t index;
224
  parseName(name,index,pname);
225
  return getFunction(index)->parameterIndex(pname) + m_paramOffsets[index];
226
227
}

Nick Draper's avatar
re #100    
Nick Draper committed
228
/// Returns the name of parameter
229
/// @param i :: The index
Nick Draper's avatar
re #100    
Nick Draper committed
230
/// @return The name of the parameter
231
std::string CompositeFunction::parameterName(size_t i)const
232
{
233
  size_t iFun = functionIndex(i);
234
235
236
  std::ostringstream ostr;
  ostr << 'f' << iFun << '.' << m_functions[ iFun ]->parameterName(i - m_paramOffsets[iFun]);
  return ostr.str();
237
238
}

239
240
241
242
243
/// Returns the description of parameter
/// @param i :: The index
/// @return The description of the parameter
std::string CompositeFunction::parameterDescription(size_t i)const
{
244
  size_t iFun = functionIndex(i);
245
246
247
248
249
  std::ostringstream ostr;
  ostr << m_functions[ iFun ]->parameterDescription(i - m_paramOffsets[iFun]);
  return ostr.str();
}

250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
/** 
 * Get the fitting error for a parameter
 * @param i :: The index of a parameter
 * @return :: the error
 */
double CompositeFunction::getError(size_t i) const
{
  size_t iFun = functionIndex(i);
  return m_functions[ iFun ]->getError(i - m_paramOffsets[iFun]);
}

/** 
 * Set the fitting error for a parameter
 * @param i :: The index of a parameter
 * @param err :: The error value to set
 */
void CompositeFunction::setError(size_t i, double err)
{
  size_t iFun = functionIndex(i);
  m_functions[ iFun ]->setError(i - m_paramOffsets[iFun], err);
}

272
/// Value of i-th active parameter. Override this method to make fitted parameters different from the declared
273
double CompositeFunction::activeParameter(size_t i)const
274
{
275
276
  size_t iFun = functionIndex(i);
  return m_functions[ iFun ]->activeParameter(i - m_paramOffsets[iFun]);
277
278
279
}

/// Set new value of i-th active parameter. Override this method to make fitted parameters different from the declared
280
void CompositeFunction::setActiveParameter(size_t i, double value)
281
{
282
283
  size_t iFun = functionIndex(i);
  m_functions[ iFun ]->setActiveParameter(i - m_paramOffsets[iFun],value);
284
285
286
}

/// Returns the name of active parameter i
287
std::string CompositeFunction::nameOfActive(size_t i)const
288
{
289
  size_t iFun = functionIndex(i);
290
  std::ostringstream ostr;
291
  ostr << 'f' << iFun << '.' << m_functions[ iFun ]->nameOfActive(i - m_paramOffsets[iFun]);
292
293
294
295
296
297
  return ostr.str();
}

/// Returns the description of active parameter i
std::string CompositeFunction::descriptionOfActive(size_t i)const
{
298
  size_t iFun = functionIndex(i);
299
  std::ostringstream ostr;
300
  ostr << m_functions[ iFun ]->descriptionOfActive(i - m_paramOffsets[iFun]);
301
  return ostr.str();
302
303
}

304
305
306
307
308
309
310
311
312
313
314
/**
 * query to see in the function is active
 * @param i :: The index of a declared parameter
 * @return true if parameter i is active
 */
bool CompositeFunction::isActive(size_t i)const
{
  size_t iFun = functionIndex(i);
  return m_functions[ iFun ]->isActive(i - m_paramOffsets[iFun]);
}

315
/**
316
 * query to see in the function is active
317
 * @param i :: The index of a declared parameter
318
 * @return true if parameter i is active
319
 */
320
bool CompositeFunction::isFixed(size_t i)const
321
{
322
  size_t iFun = functionIndex(i);
323
  return m_functions[ iFun ]->isFixed(i - m_paramOffsets[iFun]);
324
325
326
}

/**
327
 * @param i :: A declared parameter index to be removed from active
328
 */
329
void CompositeFunction::fix(size_t i)
330
{
331
  size_t iFun = functionIndex(i);
332
  m_functions[ iFun ]->fix(i - m_paramOffsets[iFun]);
333
334
}

335
/** Makes a parameter active again. It doesn't change the parameter's tie.
336
 * @param i :: A declared parameter index to be restored to active
337
 */
338
void CompositeFunction::unfix(size_t i)
339
{
340
  size_t iFun = functionIndex(i);
341
  m_functions[ iFun ]->unfix(i - m_paramOffsets[iFun]);
342
343
}

344
345
346
347
348
349
/** Makes sure that the function is consistent. 
 */
void CompositeFunction::checkFunction()
{
  m_nParams = 0;
  m_paramOffsets.clear();
350
  m_IFunction.clear();
351

352
  std::vector<IFunction_sptr> functions(m_functions.begin(),m_functions.end());
353
354
  m_functions.clear();

355
  for(std::vector<IFunction_sptr>::size_type i=0;i<functions.size();i++)
356
  {
357
358
    IFunction_sptr f = functions[i];
    CompositeFunction_sptr cf = boost::dynamic_pointer_cast<CompositeFunction>(f);
359
    if (cf) cf->checkFunction();
360
361
362
363
    addFunction(f);
  }
}

364
/** Add a function
365
 * @param f :: A pointer to the added function
366
 * @return The function index
367
 */
368
size_t CompositeFunction::addFunction(IFunction_sptr f)
369
{
370
  m_IFunction.insert(m_IFunction.end(),f->nParams(), m_functions.size());
371
372
373
374
375
376
377
378
379
380
381
382
  m_functions.push_back(f);
  //?f->init();
  if (m_paramOffsets.size() == 0)
  {
    m_paramOffsets.push_back(0);
    m_nParams = f->nParams();
  }
  else
  {
    m_paramOffsets.push_back(m_nParams);
    m_nParams += f->nParams();
  }
383
  return m_functions.size() - 1;
384
385
}

386
/** Remove a function
387
388
 * @param i :: The index of the function to remove
 * @param del :: The deletion flag. If true the function will be deleted otherwise - simply detached
389
 */
390
void CompositeFunction::removeFunction(size_t i)
391
{
392
  if ( i >= nFunctions() )
393
394
    throw std::out_of_range("Function index out of range.");

395
  IFunction_sptr fun = getFunction(i);
396

397
  size_t dnp = fun->nParams();
398

399
  for(size_t j=0;j<nParams();)
400
401
  {
    ParameterTie* tie = getTie(j);
402
    if (tie && tie->findParametersOf(fun.get()))
403
404
405
406
407
408
409
410
411
412
    {
      removeTie(j);
    }
    else
    {
      j++;
    }
  }

  // Shift down the function indeces for parameters
413
  for(std::vector<size_t>::iterator it=m_IFunction.begin();it!=m_IFunction.end();)
414
  {
415

416
417
    if (*it == i)
    {
418
      it = m_IFunction.erase(it);
419
    }
420
    else
421
    {
422
423
424
425
      if (*it > i)
      {
        *it -= 1;
      }
426
      ++it;
427
428
429
430
431
    }
  }

  m_nParams -= dnp;
  // Shift the parameter offsets down by the total number of i-th function's params
432
  for(size_t j=i+1;j<nFunctions();j++)
433
434
435
436
437
438
439
440
  {
    m_paramOffsets[j] -= dnp;
  }
  m_paramOffsets.erase(m_paramOffsets.begin()+i);

  m_functions.erase(m_functions.begin()+i);
}

441
/** Replace a function with a new one. The old function is deleted.
442
 *  The new function must have already its workspace set.
443
 * @param f_old :: The pointer to the function to replace. If it's not
444
 *  a member of this composite function nothing happens
445
 * @param f_new :: A pointer to the new function
446
 */
447
void CompositeFunction::replaceFunctionPtr(const IFunction_sptr f_old,IFunction_sptr f_new)
448
{
449
  std::vector<IFunction_sptr>::const_iterator it = 
450
451
    std::find(m_functions.begin(),m_functions.end(),f_old);
  if (it == m_functions.end()) return;
452
  std::vector<IFunction_sptr>::difference_type iFun = it - m_functions.begin();
453
  replaceFunction(iFun,f_new);
454
455
}

456
/** Replace a function with a new one. The old function is deleted.
457
458
 * @param i :: The index of the function to replace
 * @param f :: A pointer to the new function
459
 */
460
void CompositeFunction::replaceFunction(size_t i,IFunction_sptr f)
461
{
462
  if ( i >= nFunctions() )
463
464
    throw std::out_of_range("Function index out of range.");

465
  IFunction_sptr fun = getFunction(i);
466
  size_t np_old = fun->nParams();
467

468
  size_t np_new = f->nParams();
469
470
471

  // Modify function indeces: The new function may have different number of parameters
  {
472
473
    std::vector<size_t>::iterator itFun = std::find(m_IFunction.begin(),m_IFunction.end(),i);
    if(itFun != m_IFunction.end()) // functions must have at least 1 parameter
474
    {
475
476
      if (np_old > np_new)
      {
477
        m_IFunction.erase(itFun,itFun + np_old - np_new);
478
479
480
      }
      else if (np_old < np_new) 
      {
481
        m_IFunction.insert(itFun,np_new - np_old,i);
482
      }
483
    }
484
485
    else if (np_new > 0) // it could happen if the old function is an empty CompositeFunction
    {
486
487
      itFun = std::find_if(m_IFunction.begin(),m_IFunction.end(),std::bind2nd(std::greater<size_t>(),i));
      m_IFunction.insert(itFun,np_new,i);
488
    }
489
490
  }

491
  size_t dnp = np_new - np_old;
492
493
  m_nParams += dnp;
  // Shift the parameter offsets down by the total number of i-th function's params
494
  for(size_t j=i+1;j<nFunctions();j++)
495
496
497
498
499
500
501
  {
    m_paramOffsets[j] += dnp;
  }

  m_functions[i] = f;
}

502
/**
503
 * @param i :: The index of the function
504
 * @return function at the requested index
505
 */
506
IFunction_sptr CompositeFunction::getFunction(std::size_t i)const
507
{
Peterson, Peter's avatar
Peterson, Peter committed
508
  if ( i >= nFunctions() )
509
  {
510
    throw std::out_of_range("Function index out of range.");
511
  }
512
513
514
  return m_functions[i];
}

515
516
/**
 * Get the index of the function to which parameter i belongs
517
 * @param i :: The parameter index
518
 * @return function index of the requested parameter
519
 */
520
size_t CompositeFunction::functionIndex(std::size_t i)const
521
{
522
  if( i >= nParams() )
523
  {
524
    throw std::out_of_range("Function parameter index out of range.");
525
  }
526
  return m_IFunction[i];
527
528
529
}

/**
530
* @param varName :: The variable name which may contain function index ( [f<index.>]name )
531
* @param index :: Receives function index or throws std::invalid_argument
532
* @param name :: Receives the parameter name
533
*/
534
void CompositeFunction::parseName(const std::string& varName,size_t& index, std::string& name)
535
{
536
537
538
  size_t i = varName.find('.');
  if (i == std::string::npos)
  {
539
    throw std::invalid_argument("Parameter " + varName + " not found.");
540
541
542
543
544
545
  }
  else
  {
    if (varName[0] != 'f')
      throw std::invalid_argument("External function parameter name must start with 'f'");

546
    std::string sindex = varName.substr(1,i - 1);
547
548
549
550
551
552
553
    index = boost::lexical_cast<int>(sindex);

    if (i == varName.size() - 1)
      throw std::invalid_argument("Name cannot be empty");

    name = varName.substr(i+1);
  }
554
555
}

556
/** Returns the index of parameter i as it declared in its function
557
 * @param i :: The parameter index
558
559
 * @return The local index of the parameter
 */
560
size_t CompositeFunction::parameterLocalIndex(size_t i)const
561
{
562
  size_t iFun = functionIndex(i);
563
564
565
  return i - m_paramOffsets[iFun];
}

566
/** Returns the name of parameter i as it declared in its function
567
 * @param i :: The parameter index
568
569
 * @return The pure parameter name (without the function identifier f#.)
 */
570
std::string CompositeFunction::parameterLocalName(size_t i)const
571
{
572
  size_t iFun = functionIndex(i);
573
574
575
  return m_functions[ iFun ]->parameterName(i - m_paramOffsets[iFun]);
}

576
/**
577
 * Apply the ties.
578
579
580
 */
void CompositeFunction::applyTies()
{
Peterson, Peter's avatar
Peterson, Peter committed
581
  for(size_t i=0;i<nFunctions();i++)
582
583
584
585
586
587
588
589
590
591
  {
    getFunction(i)->applyTies();
  }
}

/**
 * Clear the ties. 
 */
void CompositeFunction::clearTies()
{
Peterson, Peter's avatar
Peterson, Peter committed
592
  for(size_t i=0;i<nFunctions();i++)
593
594
595
596
597
598
  {
    getFunction(i)->clearTies();
  }
}

/** Removes i-th parameter's tie if it is tied or does nothing.
599
 * @param i :: The index of the tied parameter.
600
601
 * @return True if successfull
 */
602
bool CompositeFunction::removeTie(size_t i)
603
{
604
  size_t iFun = functionIndex(i);
605
606
607
608
609
  bool res = m_functions[ iFun ]->removeTie(i - m_paramOffsets[iFun]);
  return res;
}

/** Get the tie of i-th parameter
610
 * @param i :: The parameter index
611
 * @return A pointer to the tie.
612
 */
613
ParameterTie* CompositeFunction::getTie(size_t i)const
614
{
615
  size_t iFun = functionIndex(i);
616
617
618
619
620
  return m_functions[ iFun ]->getTie(i - m_paramOffsets[iFun]);
}

/**
 * Attaches a tie to this function. The attached tie is owned by the function.
621
 * @param tie :: A pointer to a new tie
622
623
624
 */
void CompositeFunction::addTie(ParameterTie* tie)
{
625
626
  size_t i = getParameterIndex(*tie);
  size_t iFun = functionIndex(i);
627
628
629
630
631
  m_functions[iFun]->addTie(tie);
}

/**
 * Declare a new parameter. To used in the implementation'c constructor.
632
633
 * @param name :: The parameter name.
 * @param initValue :: The initial value for the parameter
634
 * @param description :: Parameter documentation
635
 */
636
void CompositeFunction::declareParameter(const std::string& name, double initValue, const std::string& description)
637
{
638
639
  (void) name; //Avoid compiler warning
  (void) initValue; //Avoid compiler warning
640
  (void) description; //Avoid compiler warning
641
642
643
644
  throw Kernel::Exception::NotImplementedError("CompositeFunction cannot not have its own parameters.");
}

/** Add a constraint
645
 *  @param ic :: Pointer to a constraint.
646
647
648
 */
void CompositeFunction::addConstraint(IConstraint* ic)
{
649
650
  size_t i = getParameterIndex(*ic);
  size_t iFun = functionIndex(i);
651
  getFunction(iFun)->addConstraint(ic);
652
653
}

654
655
656
/**
 * Prepare the function for a fit.
 */
657
void CompositeFunction::setUpForFit()
658
{
659
  // set up the member functions
Peterson, Peter's avatar
Peterson, Peter committed
660
  for(size_t i=0;i<nFunctions();i++)
661
  {
662
    getFunction(i)->setUpForFit();
663
  }
664
665
666
667
  // unfortuately the code below breaks some system tests (IRISFuryAndFuryFit)
  // it looks as if using numeric derivatives can give different fit results
  // to fit with analytical ones
  //
668
  // if parameters have non-constant ties enable numerical derivatives
669
670
671
672
673
674
675
676
677
678
679
680
681
  //for(size_t i = 0; i < nParams(); ++i)
  //{
  //  ParameterTie* tie = getTie( i );
  //  if ( tie && !tie->isConstant() )
  //  {
  //    useNumericDerivatives( true );
  //    break;
  //  }
  //}

  // instead of automatically switching to numeric derivatives
  // log a warning about a danger of not using it
  if ( !m_useNumericDerivatives ) 
682
  {
683
    for(size_t i = 0; i < nParams(); ++i)
684
    {
685
686
687
688
689
690
      ParameterTie* tie = getTie( i );
      if ( tie && !tie->isConstant() )
      {
        g_log.warning() << "Numeric derivatives should be used when non-constant ties defined." << std::endl;
        break;
      }
691
    }
692
693
694
  }
}

Nick Draper's avatar
re #100    
Nick Draper committed
695
/// Get constraint
696
/// @param i :: the index
Nick Draper's avatar
re #100    
Nick Draper committed
697
/// @return A pointer to the constraint
698
IConstraint* CompositeFunction::getConstraint(size_t i)const
699
{
700
  size_t iFun = functionIndex(i);
701
  return m_functions[ iFun ]->getConstraint(i - m_paramOffsets[iFun]);
702
703
}

704
/** Remove a constraint
705
 * @param parName :: The name of a parameter which constarint to remove.
706
707
708
 */
void CompositeFunction::removeConstraint(const std::string& parName)
{
709
710
  size_t iPar = parameterIndex(parName);
  size_t iFun = functionIndex(iPar);
711
712
713
  getFunction(iFun)->removeConstraint(parameterLocalName(iPar));
}

714
/** Checks if a constraint has been explicitly set
715
 *  @param i :: The parameter index
716
 *  @return true if the function is explicitly set
717
 */
718
bool CompositeFunction::isExplicitlySet(size_t i)const
719
{
720
  size_t iFun = functionIndex(i);
721
722
723
  return m_functions[ iFun ]->isExplicitlySet(i - m_paramOffsets[iFun]);
}

724
/**
725
 * Returns the index of parameter if the ref points to one of the member function
726
 * @param ref :: A reference to a parameter
727
 * @return Parameter index or number of nParams() if parameter not found
728
 */
729
size_t CompositeFunction::getParameterIndex(const ParameterReference& ref)const
730
{
731
  if (ref.getFunction() == this && ref.getIndex() < nParams())
732
  {
733
    return ref.getIndex();
734
  }
Peterson, Peter's avatar
Peterson, Peter committed
735
  for(size_t iFun=0;iFun<nFunctions();iFun++)
736
  {
737
    IFunction_sptr fun = getFunction(iFun);
738
739
    size_t iLocalIndex = fun->getParameterIndex(ref);
    if (iLocalIndex < fun->nParams())
740
741
742
743
    {
      return m_paramOffsets[iFun] + iLocalIndex;
    }
  }
744
  return nParams();
745
746
}

747
/**
748
 * Returns the shrared pointer to the function conataining a parameter
749
 * @param ref :: The reference
750
751
 * @return A function containing parameter pointed to by ref
 */
752
IFunction_sptr CompositeFunction::getContainingFunction(const ParameterReference& ref)const
753
{
Peterson, Peter's avatar
Peterson, Peter committed
754
  for(size_t iFun=0;iFun<nFunctions();iFun++)
755
  {
756
757
    IFunction_sptr fun = getFunction(iFun);
    if (fun->getParameterIndex(ref) < fun->nParams())
758
    {
759
      return fun;
760
761
    }
  }
762
763
764
  return IFunction_sptr();
}

765
766
767
768
769
770
771
772
773
774
/**
 * Enable/disable numeric derivative calculation.
 * @param yes :: Set to true to use numeric derivative calculation.
 */
void CompositeFunction::useNumericDerivatives( bool yes ) const
{
  m_useNumericDerivatives = yes;
}


775
776
} // namespace API
} // namespace Mantid