CompositeFunction.cpp 21.8 KB
Newer Older
1
2
3
//----------------------------------------------------------------------
// Includes
//----------------------------------------------------------------------
4
5
#include "MantidAPI/CompositeFunction.h"
#include "MantidAPI/ParameterTie.h"
6
#include "MantidAPI/IConstraint.h"
7
#include "MantidAPI/FunctionFactory.h"
Gigg, Martyn Anthony's avatar
Gigg, Martyn Anthony committed
8
9
10
#include "MantidKernel/Exception.h"
#include "MantidKernel/Logger.h"

11

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

namespace Mantid
{
namespace API
{

Gigg, Martyn Anthony's avatar
Gigg, Martyn Anthony committed
23
24
25
26
27
28
  namespace
  {
    /// static logger
    Kernel::Logger g_log("CompositeFunction");
  }

Peterson, Peter's avatar
Peterson, Peter committed
29
30
using std::size_t;

31
DECLARE_FUNCTION(CompositeFunction)
32

33
/// Default constructor
34
35
CompositeFunction::CompositeFunction()
  : IFunction(), m_nParams(0)
36
37
38
39
{
  declareAttribute("NumDeriv", Attribute(false));
}

40
41
42
43
44
45
46
47
48
49
///Destructor
CompositeFunction::~CompositeFunction()
{
}

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

50
51
52
53
54
55
56
57
58
59
60
/** 
 * 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=(" << ... <<")";
 *   }
61
 * @return the string representation of the composite function
62
 */
63
64
65
std::string CompositeFunction::asString()const
{
  std::ostringstream ostr;
66
67
68
69
70
71
72
  
  // if empty just return function name
  if (nFunctions() == 0)
  {
    return "name=" + name();
  }

73
  if ( name() != "CompositeFunction" || nAttributes() > 1 || getAttribute("NumDeriv").asBool() == true )
74
  {
75
76
77
78
79
80
81
82
83
84
85
86
    ostr << "composite=" <<name() ;
    std::vector<std::string> attr = this->getAttributeNames();
    for(size_t i=0;i<attr.size();i++)
    {
      std::string attName = attr[i];
      std::string attValue = this->getAttribute(attr[i]).value();
      if (!attValue.empty())
      {
        ostr<<','<<attName<<'='<<attValue;
      }
    }
    ostr << ';';
87
  }
Peterson, Peter's avatar
Peterson, Peter committed
88
  for(size_t i=0;i<nFunctions();i++)
89
  {
90
91
    IFunction_sptr fun = getFunction(i);
    bool isComp = boost::dynamic_pointer_cast<CompositeFunction>(fun) != 0;
92
    if (isComp) ostr << '(';
93
    ostr << fun->asString();
94
    if (isComp) ostr << ')';
95
96
97
98
99
100
    if (i < nFunctions() - 1)
    {
      ostr << ';';
    }
  }
  std::string ties;
101
  for(size_t i=0;i<nParams();i++)
102
103
104
105
  {
    const ParameterTie* tie = getTie(i);
    if (tie)
    {
106
107
      IFunction_sptr fun = getFunction(functionIndex(i));
      std::string tmp = tie->asString(fun.get());
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
      if (tmp.empty())
      {
        tmp = tie->asString(this);
        if (!tmp.empty())
        {
          if (!ties.empty())
          {
            ties += ",";
          }
          ties += tmp;
        }
      }
    }
  }
  if (!ties.empty())
  {
    ostr << ";ties=(" << ties << ")";
125
126
127
128
  }
  return ostr.str();
}

129
130
131
132
133
134
135
136
137
138
139
140
141
/**
 * @param ws A pointer to the workspace being fitted
 */
void CompositeFunction::setWorkspace(boost::shared_ptr<const Workspace> ws)
{
  // Pass it on to each member
  auto iend = m_functions.end();
  for(auto it = m_functions.begin(); it != iend; ++it)
  {
    (*it)->setWorkspace(ws);
  }
}

142
143
144
145
146
147
148
149
150
151
152
153
154
155
/**
 * @param workspace :: A workspace to fit to.
 * @param wi :: An index of a spectrum to fit to.
 * @param startX :: A start of the fitting region.
 * @param endX :: An end of the fitting region.
 */
void CompositeFunction::setMatrixWorkspace(boost::shared_ptr<const MatrixWorkspace> workspace, size_t wi, double startX, double endX)
{
    for(size_t iFun = 0; iFun < nFunctions(); ++iFun)
    {
        m_functions[ iFun ]->setMatrixWorkspace( workspace, wi, startX, endX );
    }
}

156
/** Function you want to fit to. 
157
158
 *  @param domain :: An instance of FunctionDomain with the function arguments.
 *  @param values :: A FunctionValues instance for storing the calculated values.
159
160
161
162
 */
void CompositeFunction::function(const FunctionDomain& domain, FunctionValues& values)const
{
  FunctionValues tmp(domain);
163
  values.zeroCalculated();
164
165
166
167
168
169
170
171
172
173
174
175
176
177
  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)
{
178
  if ( getAttribute("NumDeriv").asBool() )
179
180
181
182
  {
    calNumericalDeriv(domain, jacobian);
  }
  else
183
  {
184
185
186
187
188
    for(size_t iFun = 0; iFun < nFunctions(); ++iFun)
    {
      PartialJacobian J(&jacobian,paramOffset(iFun));
      getFunction(iFun)->functionDeriv(domain,J);
    }
189
190
191
  }
}

192
/** Sets a new value to the i-th parameter.
193
194
195
 *  @param i :: The parameter index
 *  @param value :: The new value
 *  @param explicitlySet :: A boolean falgging the parameter as explicitly set (by user)
196
 */
197
void CompositeFunction::setParameter(size_t i, const double& value, bool explicitlySet)
198
{
199
  size_t iFun = functionIndex(i);
200
  m_functions[ iFun ]->setParameter(i - m_paramOffsets[iFun],value,explicitlySet);
201
202
}

203
204
205
206
207
208
/** 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)
{
209
  size_t iFun = functionIndex(i);
210
211
212
  m_functions[ iFun ]->setParameterDescription(i - m_paramOffsets[iFun],description);
}

213
/** Get the i-th parameter.
214
 *  @param i :: The parameter index
215
 *  @return value of the requested parameter
216
 */
217
double CompositeFunction::getParameter(size_t i)const
218
{
Peterson, Peter's avatar
Peterson, Peter committed
219
  size_t iFun = functionIndex(i);
220
  return m_functions[ iFun ]->getParameter(i - m_paramOffsets[iFun]);
221
222
}

223
224
/**
 * Sets a new value to a parameter by name.
225
226
227
 * @param name :: The name of the parameter.
 * @param value :: The new value
 * @param explicitlySet :: A boolean falgging the parameter as explicitly set (by user)
228
229
 */
void CompositeFunction::setParameter(const std::string& name, const double& value, bool explicitlySet)
230
{
231
  std::string pname;
232
  size_t index;
233
  parseName(name,index,pname);
234
  getFunction(index)->setParameter(pname,value,explicitlySet);
235
236
}

237
238
239
/**
 * Sets a new description to a parameter by name.
 * @param name :: The name of the parameter.
240
 * @param description :: The new description
241
242
243
244
 */
void CompositeFunction::setParameterDescription(const std::string& name, const std::string& description)
{
  std::string pname;
245
  size_t index;
246
  parseName(name,index,pname);
247
  getFunction(index)->setParameterDescription(pname,description);
248
249
}

250
251
/**
 * Parameters by name.
252
 * @param name :: The name of the parameter.
253
 * @return value of the requested named parameter
254
 */
255
256
double CompositeFunction::getParameter(const std::string& name)const
{
257
  std::string pname;
258
  size_t index;
259
  parseName(name,index,pname);
260
  return getFunction(index)->getParameter(pname);
261
262
263
}

/// Total number of parameters
264
size_t CompositeFunction::nParams()const
265
266
267
268
{
  return m_nParams;
}

269
/**
270
 * 
271
 * @param name :: The name of a parameter
272
 * @return index of the requested named parameter
273
 */
274
size_t CompositeFunction::parameterIndex(const std::string& name)const
275
{
276
  std::string pname;
277
  size_t index;
278
  parseName(name,index,pname);
279
  return getFunction(index)->parameterIndex(pname) + m_paramOffsets[index];
280
281
}

Nick Draper's avatar
re #100    
Nick Draper committed
282
/// Returns the name of parameter
283
/// @param i :: The index
Nick Draper's avatar
re #100    
Nick Draper committed
284
/// @return The name of the parameter
285
std::string CompositeFunction::parameterName(size_t i)const
286
{
287
  size_t iFun = functionIndex(i);
288
289
290
  std::ostringstream ostr;
  ostr << 'f' << iFun << '.' << m_functions[ iFun ]->parameterName(i - m_paramOffsets[iFun]);
  return ostr.str();
291
292
}

293
294
295
296
297
/// Returns the description of parameter
/// @param i :: The index
/// @return The description of the parameter
std::string CompositeFunction::parameterDescription(size_t i)const
{
298
  size_t iFun = functionIndex(i);
299
300
301
302
303
  std::ostringstream ostr;
  ostr << m_functions[ iFun ]->parameterDescription(i - m_paramOffsets[iFun]);
  return ostr.str();
}

304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
/** 
 * 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);
}

326
/// Value of i-th active parameter. Override this method to make fitted parameters different from the declared
327
double CompositeFunction::activeParameter(size_t i)const
328
{
329
330
  size_t iFun = functionIndex(i);
  return m_functions[ iFun ]->activeParameter(i - m_paramOffsets[iFun]);
331
332
333
}

/// Set new value of i-th active parameter. Override this method to make fitted parameters different from the declared
334
void CompositeFunction::setActiveParameter(size_t i, double value)
335
{
336
337
  size_t iFun = functionIndex(i);
  m_functions[ iFun ]->setActiveParameter(i - m_paramOffsets[iFun],value);
338
339
340
}

/// Returns the name of active parameter i
341
std::string CompositeFunction::nameOfActive(size_t i)const
342
{
343
  size_t iFun = functionIndex(i);
344
  std::ostringstream ostr;
345
  ostr << 'f' << iFun << '.' << m_functions[ iFun ]->nameOfActive(i - m_paramOffsets[iFun]);
346
347
348
349
350
351
  return ostr.str();
}

/// Returns the description of active parameter i
std::string CompositeFunction::descriptionOfActive(size_t i)const
{
352
  size_t iFun = functionIndex(i);
353
  std::ostringstream ostr;
354
  ostr << m_functions[ iFun ]->descriptionOfActive(i - m_paramOffsets[iFun]);
355
  return ostr.str();
356
357
}

358
359
360
361
362
363
364
365
366
367
368
/**
 * 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]);
}

369
/**
370
 * query to see in the function is active
371
 * @param i :: The index of a declared parameter
372
 * @return true if parameter i is active
373
 */
374
bool CompositeFunction::isFixed(size_t i)const
375
{
376
  size_t iFun = functionIndex(i);
377
  return m_functions[ iFun ]->isFixed(i - m_paramOffsets[iFun]);
378
379
380
}

/**
381
 * @param i :: A declared parameter index to be removed from active
382
 */
383
void CompositeFunction::fix(size_t i)
384
{
385
  size_t iFun = functionIndex(i);
386
  m_functions[ iFun ]->fix(i - m_paramOffsets[iFun]);
387
388
}

389
/** Makes a parameter active again. It doesn't change the parameter's tie.
390
 * @param i :: A declared parameter index to be restored to active
391
 */
392
void CompositeFunction::unfix(size_t i)
393
{
394
  size_t iFun = functionIndex(i);
395
  m_functions[ iFun ]->unfix(i - m_paramOffsets[iFun]);
396
397
}

398
399
400
401
402
403
/** Makes sure that the function is consistent. 
 */
void CompositeFunction::checkFunction()
{
  m_nParams = 0;
  m_paramOffsets.clear();
404
  m_IFunction.clear();
405

406
  std::vector<IFunction_sptr> functions(m_functions.begin(),m_functions.end());
407
408
  m_functions.clear();

409
  for(std::vector<IFunction_sptr>::size_type i=0;i<functions.size();i++)
410
  {
411
412
    IFunction_sptr f = functions[i];
    CompositeFunction_sptr cf = boost::dynamic_pointer_cast<CompositeFunction>(f);
413
    if (cf) cf->checkFunction();
414
415
416
417
    addFunction(f);
  }
}

418
/** Add a function
419
 * @param f :: A pointer to the added function
420
 * @return The function index
421
 */
422
size_t CompositeFunction::addFunction(IFunction_sptr f)
423
{
424
  m_IFunction.insert(m_IFunction.end(),f->nParams(), m_functions.size());
425
426
427
428
429
430
431
432
433
434
435
436
  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();
  }
437
  return m_functions.size() - 1;
438
439
}

440
/** Remove a function
441
 * @param i :: The index of the function to remove
442
 */
443
void CompositeFunction::removeFunction(size_t i)
444
{
445
  if ( i >= nFunctions() )
446
447
    throw std::out_of_range("Function index out of range.");

448
  IFunction_sptr fun = getFunction(i);
449

450
  size_t dnp = fun->nParams();
451

452
  for(size_t j=0;j<nParams();)
453
454
  {
    ParameterTie* tie = getTie(j);
455
    if (tie && tie->findParametersOf(fun.get()))
456
457
458
459
460
461
462
463
464
465
    {
      removeTie(j);
    }
    else
    {
      j++;
    }
  }

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

469
470
    if (*it == i)
    {
471
      it = m_IFunction.erase(it);
472
    }
473
    else
474
    {
475
476
477
478
      if (*it > i)
      {
        *it -= 1;
      }
479
      ++it;
480
481
482
483
484
    }
  }

  m_nParams -= dnp;
  // Shift the parameter offsets down by the total number of i-th function's params
485
  for(size_t j=i+1;j<nFunctions();j++)
486
487
488
489
490
491
492
493
  {
    m_paramOffsets[j] -= dnp;
  }
  m_paramOffsets.erase(m_paramOffsets.begin()+i);

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

494
/** Replace a function with a new one. The old function is deleted.
495
 *  The new function must have already its workspace set.
496
 * @param f_old :: The pointer to the function to replace. If it's not
497
 *  a member of this composite function nothing happens
498
 * @param f_new :: A pointer to the new function
499
 */
500
void CompositeFunction::replaceFunctionPtr(const IFunction_sptr f_old,IFunction_sptr f_new)
501
{
502
  std::vector<IFunction_sptr>::const_iterator it = 
503
504
    std::find(m_functions.begin(),m_functions.end(),f_old);
  if (it == m_functions.end()) return;
505
  std::vector<IFunction_sptr>::difference_type iFun = it - m_functions.begin();
506
  replaceFunction(iFun,f_new);
507
508
}

509
/** Replace a function with a new one. The old function is deleted.
510
511
 * @param i :: The index of the function to replace
 * @param f :: A pointer to the new function
512
 */
513
void CompositeFunction::replaceFunction(size_t i,IFunction_sptr f)
514
{
515
  if ( i >= nFunctions() )
516
517
    throw std::out_of_range("Function index out of range.");

518
  IFunction_sptr fun = getFunction(i);
519
  size_t np_old = fun->nParams();
520

521
  size_t np_new = f->nParams();
522
523
524

  // Modify function indeces: The new function may have different number of parameters
  {
525
526
    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
527
    {
528
529
      if (np_old > np_new)
      {
530
        m_IFunction.erase(itFun,itFun + np_old - np_new);
531
532
533
      }
      else if (np_old < np_new) 
      {
534
        m_IFunction.insert(itFun,np_new - np_old,i);
535
      }
536
    }
537
538
    else if (np_new > 0) // it could happen if the old function is an empty CompositeFunction
    {
539
540
      itFun = std::find_if(m_IFunction.begin(),m_IFunction.end(),std::bind2nd(std::greater<size_t>(),i));
      m_IFunction.insert(itFun,np_new,i);
541
    }
542
543
  }

544
  size_t dnp = np_new - np_old;
545
546
  m_nParams += dnp;
  // Shift the parameter offsets down by the total number of i-th function's params
547
  for(size_t j=i+1;j<nFunctions();j++)
548
549
550
551
552
553
554
  {
    m_paramOffsets[j] += dnp;
  }

  m_functions[i] = f;
}

555
/**
556
 * @param i :: The index of the function
557
 * @return function at the requested index
558
 */
559
IFunction_sptr CompositeFunction::getFunction(std::size_t i)const
560
{
Peterson, Peter's avatar
Peterson, Peter committed
561
  if ( i >= nFunctions() )
562
  {
563
    throw std::out_of_range("Function index out of range.");
564
  }
565
566
567
  return m_functions[i];
}

568
569
/**
 * Get the index of the function to which parameter i belongs
570
 * @param i :: The parameter index
571
 * @return function index of the requested parameter
572
 */
573
size_t CompositeFunction::functionIndex(std::size_t i)const
574
{
575
  if( i >= nParams() )
576
  {
577
    throw std::out_of_range("Function parameter index out of range.");
578
  }
579
  return m_IFunction[i];
580
581
582
}

/**
583
* @param varName :: The variable name which may contain function index ( [f<index.>]name )
584
* @param index :: Receives function index or throws std::invalid_argument
585
* @param name :: Receives the parameter name
586
*/
587
void CompositeFunction::parseName(const std::string& varName,size_t& index, std::string& name)
588
{
589
590
591
  size_t i = varName.find('.');
  if (i == std::string::npos)
  {
592
    throw std::invalid_argument("Parameter " + varName + " not found.");
593
594
595
596
597
598
  }
  else
  {
    if (varName[0] != 'f')
      throw std::invalid_argument("External function parameter name must start with 'f'");

599
    std::string sindex = varName.substr(1,i - 1);
600
601
602
603
604
605
606
    index = boost::lexical_cast<int>(sindex);

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

    name = varName.substr(i+1);
  }
607
608
}

609
/** Returns the index of parameter i as it declared in its function
610
 * @param i :: The parameter index
611
612
 * @return The local index of the parameter
 */
613
size_t CompositeFunction::parameterLocalIndex(size_t i)const
614
{
615
  size_t iFun = functionIndex(i);
616
617
618
  return i - m_paramOffsets[iFun];
}

619
/** Returns the name of parameter i as it declared in its function
620
 * @param i :: The parameter index
621
622
 * @return The pure parameter name (without the function identifier f#.)
 */
623
std::string CompositeFunction::parameterLocalName(size_t i)const
624
{
625
  size_t iFun = functionIndex(i);
626
627
628
  return m_functions[ iFun ]->parameterName(i - m_paramOffsets[iFun]);
}

629
/**
630
 * Apply the ties.
631
632
633
 */
void CompositeFunction::applyTies()
{
Peterson, Peter's avatar
Peterson, Peter committed
634
  for(size_t i=0;i<nFunctions();i++)
635
636
637
638
639
640
641
642
643
644
  {
    getFunction(i)->applyTies();
  }
}

/**
 * Clear the ties. 
 */
void CompositeFunction::clearTies()
{
Peterson, Peter's avatar
Peterson, Peter committed
645
  for(size_t i=0;i<nFunctions();i++)
646
647
648
649
650
651
  {
    getFunction(i)->clearTies();
  }
}

/** Removes i-th parameter's tie if it is tied or does nothing.
652
 * @param i :: The index of the tied parameter.
653
654
 * @return True if successfull
 */
655
bool CompositeFunction::removeTie(size_t i)
656
{
657
  size_t iFun = functionIndex(i);
658
659
660
661
662
  bool res = m_functions[ iFun ]->removeTie(i - m_paramOffsets[iFun]);
  return res;
}

/** Get the tie of i-th parameter
663
 * @param i :: The parameter index
664
 * @return A pointer to the tie.
665
 */
666
ParameterTie* CompositeFunction::getTie(size_t i)const
667
{
668
  size_t iFun = functionIndex(i);
669
670
671
672
673
  return m_functions[ iFun ]->getTie(i - m_paramOffsets[iFun]);
}

/**
 * Attaches a tie to this function. The attached tie is owned by the function.
674
 * @param tie :: A pointer to a new tie
675
676
677
 */
void CompositeFunction::addTie(ParameterTie* tie)
{
678
679
  size_t i = getParameterIndex(*tie);
  size_t iFun = functionIndex(i);
680
681
682
683
684
  m_functions[iFun]->addTie(tie);
}

/**
 * Declare a new parameter. To used in the implementation'c constructor.
685
686
 * @param name :: The parameter name.
 * @param initValue :: The initial value for the parameter
687
 * @param description :: Parameter documentation
688
 */
689
void CompositeFunction::declareParameter(const std::string& name, double initValue, const std::string& description)
690
{
691
692
  (void) name; //Avoid compiler warning
  (void) initValue; //Avoid compiler warning
693
  (void) description; //Avoid compiler warning
694
695
696
697
  throw Kernel::Exception::NotImplementedError("CompositeFunction cannot not have its own parameters.");
}

/** Add a constraint
698
 *  @param ic :: Pointer to a constraint.
699
700
701
 */
void CompositeFunction::addConstraint(IConstraint* ic)
{
702
703
  size_t i = getParameterIndex(*ic);
  size_t iFun = functionIndex(i);
704
  getFunction(iFun)->addConstraint(ic);
705
706
}

707
708
709
/**
 * Prepare the function for a fit.
 */
710
void CompositeFunction::setUpForFit()
711
{
712
  // set up the member functions
Peterson, Peter's avatar
Peterson, Peter committed
713
  for(size_t i=0;i<nFunctions();i++)
714
  {
715
    getFunction(i)->setUpForFit();
716
  }
717
718
719
720
  // 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
  //
721
  // if parameters have non-constant ties enable numerical derivatives
722
723
724
725
726
727
728
729
730
731
732
733
  //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
734
  if ( !getAttribute("NumDeriv").asBool() )
735
  {
736
    for(size_t i = 0; i < nParams(); ++i)
737
    {
738
739
740
741
742
743
      ParameterTie* tie = getTie( i );
      if ( tie && !tie->isConstant() )
      {
        g_log.warning() << "Numeric derivatives should be used when non-constant ties defined." << std::endl;
        break;
      }
744
    }
745
746
747
  }
}

Nick Draper's avatar
re #100    
Nick Draper committed
748
/// Get constraint
749
/// @param i :: the index
Nick Draper's avatar
re #100    
Nick Draper committed
750
/// @return A pointer to the constraint
751
IConstraint* CompositeFunction::getConstraint(size_t i)const
752
{
753
  size_t iFun = functionIndex(i);
754
  return m_functions[ iFun ]->getConstraint(i - m_paramOffsets[iFun]);
755
756
}

757
/** Remove a constraint
758
 * @param parName :: The name of a parameter which constarint to remove.
759
760
761
 */
void CompositeFunction::removeConstraint(const std::string& parName)
{
762
763
  size_t iPar = parameterIndex(parName);
  size_t iFun = functionIndex(iPar);
764
765
766
  getFunction(iFun)->removeConstraint(parameterLocalName(iPar));
}

767
/** Checks if a constraint has been explicitly set
768
 *  @param i :: The parameter index
769
 *  @return true if the function is explicitly set
770
 */
771
bool CompositeFunction::isExplicitlySet(size_t i)const
772
{
773
  size_t iFun = functionIndex(i);
774
775
776
  return m_functions[ iFun ]->isExplicitlySet(i - m_paramOffsets[iFun]);
}

777
/**
778
 * Returns the index of parameter if the ref points to one of the member function
779
 * @param ref :: A reference to a parameter
780
 * @return Parameter index or number of nParams() if parameter not found
781
 */
782
size_t CompositeFunction::getParameterIndex(const ParameterReference& ref)const
783
{
784
  if (ref.getFunction() == this && ref.getIndex() < nParams())
785
  {
786
    return ref.getIndex();
787
  }
Peterson, Peter's avatar
Peterson, Peter committed
788
  for(size_t iFun=0;iFun<nFunctions();iFun++)
789
  {
790
    IFunction_sptr fun = getFunction(iFun);
791
792
    size_t iLocalIndex = fun->getParameterIndex(ref);
    if (iLocalIndex < fun->nParams())
793
794
795
796
    {
      return m_paramOffsets[iFun] + iLocalIndex;
    }
  }
797
  return nParams();
798
799
}

800
/**
801
 * Returns the shrared pointer to the function conataining a parameter
802
 * @param ref :: The reference
803
804
 * @return A function containing parameter pointed to by ref
 */
805
IFunction_sptr CompositeFunction::getContainingFunction(const ParameterReference& ref)const
806
{
Peterson, Peter's avatar
Peterson, Peter committed
807
  for(size_t iFun=0;iFun<nFunctions();iFun++)
808
  {
809
810
    IFunction_sptr fun = getFunction(iFun);
    if (fun->getParameterIndex(ref) < fun->nParams())
811
    {
812
      return fun;
813
814
    }
  }
815
816
817
  return IFunction_sptr();
}

818
819
} // namespace API
} // namespace Mantid