source: trunk/GSASIImapvars.py @ 1785

Last change on this file since 1785 was 1778, checked in by vondreele, 10 years ago

allow Refine texture menu item to appear; use DestroyChildren? to clear the Texture tab before filling
fix azimuth calculations after image integration
put Azimuth in Sample parms.
add 3 prints to debug option in G2mapvars
add Omega, Chi, Phi & Azimuth to sequential results table if they vary

  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Author Revision URL Id
File size: 50.6 KB
Line 
1# -*- coding: utf-8 -*-
2########### SVN repository information ###################
3# $Date: 2015-04-06 18:33:00 +0000 (Mon, 06 Apr 2015) $
4# $Author: vondreele $
5# $Revision: 1778 $
6# $URL: trunk/GSASIImapvars.py $
7# $Id: GSASIImapvars.py 1778 2015-04-06 18:33:00Z vondreele $
8########### SVN repository information ###################
9"""
10*GSASIImapvars: Parameter constraints*
11======================================
12
13Module to implements algebraic contraints, parameter redefinition
14and parameter simplification contraints.
15
16Parameter redefinition (new vars) is done by creating one or more relationships
17between a set of parameters
18
19::
20
21   Mx1 * Px + My1 * Py +...
22   Mx2 * Px + Mz2 * Pz + ...
23
24where Pj is a parameter name and Mjk is a constant.
25
26Constant constraint Relations can also be supplied in the form of an equation:
27
28::
29
30  nx1 * Px + ny1 * Py +... = C1
31
32where Cn is a constant. These equations define an algebraic
33constrant.
34
35Parameters can also be "fixed" (held), which prevents them from being refined.
36
37All of the above three cases are input using routines
38GroupConstraints and GenerateConstraints. The input consists of a list of
39relationship dictionaries:
40
41.. code-block:: python
42
43    constrDict = [
44         {'0:12:Scale': 2.0, '0:14:Scale': 4.0, '0:13:Scale': 3.0, '0:0:Scale': 0.5},
45         {'2::C(10,6,1)': 1.0, '1::C(10,6,1)': 1.0},
46         {'0::A0': 0.0}]
47    fixedList = ['5.0', None, '0']
48
49Where the dictionary defines the first part of an expression and the corresponding fixedList
50item is either None (for parameter redefinition) or the constant value, for a constant
51constraint equation. A dictionary that contains a single term defines a variable that
52will be fixed (held). The multiplier and the fixedList value in this case are ignored.
53
54Parameters can also be equivalenced or "slaved" to another parameter, such that one
55(independent) parameter is equated to several (now dependent) parameters. In
56algebraic form this is:
57
58::
59
60   P0 = M1 * P1 = M2 * P2 = ...
61
62Thus parameters P0, P1 and P2,... are linearly equivalent. Routine StoreEquivalence is
63used to specify these equivalences.
64
65Parameter redefinition (new vars) describes a new, independent, parameter, which
66is defined in terms of dependent parameters that are defined in the
67Model, while fixed constrained relations effectively reduce the complexity
68of the Model by removing a degree of freedom. It is possible for a parameter to appear
69in both a parameter redefinition expression and a fixed constraint equation, but a
70parameter cannot be used a parameter equivalance cannot be used elsewhere (not fixed,
71constrained or redefined). Likewise a fixed parameter cannot be used elsewhere (not
72equivalanced, constrained or redefined).
73
74Relationships are grouped so that a set of dependent parameters appear
75in only one group (done in routine GroupConstraints.) Note that if a
76group contains relationships/equations that involve N dependent
77parameters, there must exist N-C new parameters, where C is the number
78of contraint equations in the group. Routine GenerateConstraints takes
79the output from GroupConstraints and generates the
80"missing" relationships and saves that information in the module's
81global variables. Each generated parameter is named sequentially using paramPrefix.
82
83A list of parameters that will be varied is specified as input to GenerateConstraints
84(varyList). A fixed parameter will simply be removed from this list preventing that
85parameter from being varied. Note that all parameters in a constraint relationship
86must specified as varied (appear in varyList) or none can be varied. This is
87checked in GenerateConstraints. Likewise, if all parameters in a constraint are
88not referenced in a refinement, the constraint is ignored, but if some parameters
89in a constraint group are not referenced in a refinement, but others are this
90constitutes and error.
91
92* When a new variable is created, the variable is assigned the name associated
93  in the constraint definition or it is assigned a default name of form
94  ``::constr<n>`` (see paramPrefix). The vary setting for variables used in the
95  constraint are ignored.
96  Note that any generated "missing" relations are not varied. Only
97  the input relations can be are varied.
98 
99* If all parameters in a fixed constraint equation are varied, the generated "missing"
100  relations in the group are all varied. This provides the N-C degrees of freedom.
101
102*External Routines*
103-------------------
104
105To define a set of constrained and unconstrained relations, one
106defines a list of dictionary defining constraint parameters and their
107values, a list of fixed values for each constraint and a list of
108parameters to be varied. In addition, one uses
109:func:`StoreEquivalence` to define parameters that are equivalent. One
110can then use :func:`CheckConstraints` to check that the input is
111internally consistent and finally :func:`GroupConstraints` and
112:func:`GenerateConstraints` to generate the internally used
113tables. Routines :func:`Map2Dict` is used to initialize the parameter
114dictionary and :func:`Dict2Map`, :func:`Dict2Deriv`, and
115:func:`ComputeDepESD` are used to apply constraints. Routine
116:func:`VarRemapShow` is used to print out the constraint information,
117as stored by :func:`GenerateConstraints`.
118
119:func:`InitVars`
120  This is optionally used to clear out all defined previously defined constraint information
121 
122:func:`StoreEquivalence`
123  To implement parameter redefinition, one calls StoreEquivalence. This should be called for every set of
124  equivalence relationships. There is no harm in using StoreEquivalence with the same independent variable:
125
126  .. code-block:: python
127
128       StoreEquivalence('x',('y',))
129       StoreEquivalence('x',('z',))
130
131  or equivalently
132
133  .. code-block:: python
134
135       StoreEquivalence('x',('y','z'))
136
137  The latter will run more efficiently. Note that mixing independent and dependent variables is
138  problematic. This is not allowed:
139
140  .. code-block:: python
141
142        StoreEquivalence('x',('y',))
143        StoreEquivalence('y',('z',))
144       
145  Use StoreEquivalence before calling GenerateConstraints or CheckConstraints
146
147:func:`CheckConstraints`
148   To check that input in internally consistent, use CheckConstraints
149
150:func:`Map2Dict`
151   To determine values for the parameters created in this module, one
152   calls Map2Dict. This will not apply contraints.
153
154:func:`Dict2Map`
155   To take values from the new independent parameters and constraints,
156   one calls Dict2Map. This will apply contraints.
157
158:func:`Dict2Deriv`
159   Use Dict2Deriv to determine derivatives on independent parameters
160   from those on dependent ones
161
162:func:`ComputeDepESD`     
163   Use ComputeDepESD to compute uncertainties on dependent variables
164
165:func:`VarRemapShow`
166   To show a summary of the parameter remapping, one calls VarRemapShow
167
168*Global Variables*
169------------------
170
171dependentParmList:
172   contains a list by group of lists of
173   parameters used in the group. Note that parameters listed in
174   dependentParmList should not be refined as they will not affect
175   the model
176
177indParmList:
178     a list of groups of Independent parameters defined in
179     each group. This contains both parameters used in parameter
180     redefinitions as well as names of generated new parameters.
181
182fixedVarList:
183     a list of variables that have been 'fixed'
184     by defining them as equal to a constant (::var: = 0). Note that
185     the constant value is ignored at present. These variables are
186     later removed from varyList which prevents them from being refined.
187     Unlikely to be used externally.
188
189arrayList:
190     a list by group of relationship matrices to relate
191     parameters in dependentParmList to those in indParmList. Unlikely
192     to be used externally.
193
194invarrayList:
195     a list by group of relationship matrices to relate
196     parameters in indParmList to those in dependentParmList. Unlikely
197     to be used externally.
198
199fixedDict:
200     a dictionary containing the fixed values corresponding
201     to parameter equations.  The dict key is an ascii string, but the
202     dict value is a float.  Unlikely to be used externally.
203
204*Routines*
205----------
206
207Note that parameter names in GSAS-II are strings of form ``<ph>:<hst>:<nam>``
208
209"""
210
211import numpy as np
212import GSASIIpath
213GSASIIpath.SetVersionNumber("$Revision: 1778 $")
214# data used for constraints;
215debug = False # turns on printing as constraint input is processed
216# note that constraints are stored listed by contraint groups, where each constraint
217# group contains those parameters that must be handled together
218dependentParmList = [] # contains a list of parameters in each group
219# note that parameters listed in dependentParmList should not be refined
220arrayList = [] # a list of of relationship matrices
221invarrayList = [] # a list of inverse relationship matrices
222indParmList = [] # a list of names for the new parameters
223fixedDict = {} # a dictionary containing the fixed values corresponding to defined parameter equations
224               # key is original ascii string, value is float
225fixedVarList = [] # List of variables that should not be refined
226
227# prefix for parameter names
228paramPrefix = "::constr"
229consNum = 0 # number of the next constraint to be created
230
231def InitVars():
232    '''Initializes all constraint information'''
233    global dependentParmList,arrayList,invarrayList,indParmList,fixedDict,consNum
234    dependentParmList = [] # contains a list of parameters in each group
235    arrayList = [] # a list of of relationship matrices
236    invarrayList = [] # a list of inverse relationship matrices
237    indParmList = [] # a list of names for the new parameters
238    fixedDict = {} # a dictionary containing the fixed values corresponding to defined parameter equations
239    consNum = 0 # number of the next constraint to be created
240    fixedVarList = []
241
242def VarKeys(constr):
243    """Finds the keys in a constraint that represent variables
244    e.g. eliminates any that start with '_'
245
246    :param dict constr: a single constraint entry of form::
247
248        {'var1': mult1, 'var2': mult2,... '_notVar': val,...}
249
250        (see :func:`GroupConstraints`)
251    :returns: a list of keys where any keys beginning with '_' are
252      removed.
253    """
254    return [i for i in constr.keys() if not i.startswith('_')]
255
256
257def GroupConstraints(constrDict):
258    """divide the constraints into groups that share no parameters.
259
260    :param dict constrDict: a list of dicts defining relationships/constraints
261
262    ::
263   
264       constrDict = [{<constr1>}, {<constr2>}, ...]
265
266    where {<constr1>} is {'var1': mult1, 'var2': mult2,... }
267
268    :returns: two lists of lists:
269   
270      * a list of grouped contraints where each constraint grouped containts a list
271        of indices for constraint constrDict entries
272      * a list containing lists of parameter names contained in each group
273     
274      """
275    assignedlist = [] # relationships that have been used
276    groups = [] # contains a list of grouplists
277    ParmList = []
278    for i,consi in enumerate(constrDict):
279        if i in assignedlist: continue # already in a group, skip
280        # starting a new group
281        grouplist = [i,]
282        assignedlist.append(i)
283        groupset = set(VarKeys(consi))
284        changes = True # always loop at least once
285        while(changes): # loop until we can't find anything to add to the current group
286            changes = False # but don't loop again unless we find something
287            for j,consj in enumerate(constrDict):
288                if j in assignedlist: continue # already in a group, skip
289                if len(set(VarKeys(consj)) & groupset) > 0: # true if this needs to be added
290                    changes = True
291                    grouplist.append(j)
292                    assignedlist.append(j)
293                    groupset = groupset | set(VarKeys(consj))
294        group = sorted(grouplist)
295        varlist = sorted(list(groupset))
296        groups.append(group)
297        ParmList.append(varlist)
298    return groups,ParmList
299
300def CheckConstraints(varyList,constrDict,fixedList):
301    '''Takes a list of relationship entries comprising a group of
302    constraints and checks for inconsistencies such as conflicts in
303    parameter/variable definitions and or inconsistently varied parameters.
304
305    :param list varyList: a list of parameters names that will be varied
306
307    :param dict constrDict: a list of dicts defining relationships/constraints
308      (as created in :func:`GSASIIstrIO.ProcessConstraints` and
309      documented in :func:`GroupConstraints`)
310
311    :param list fixedList: a list of values specifying a fixed value for each
312      dict in constrDict. Values are either strings that can be converted to
313      floats or ``None`` if the constraint defines a new parameter rather
314      than a constant.
315
316    :returns: two strings:
317
318      * the first lists conflicts internal to the specified constraints
319      * the second lists conflicts where the varyList specifies some
320        parameters in a constraint, but not all
321       
322      If there are no errors, both strings will be empty
323    '''
324    import re
325    global dependentParmList,arrayList,invarrayList,indParmList,consNum
326    errmsg = ''
327    warnmsg = ''
328    fixVlist = []
329    # process fixed variables (holds)
330    for cdict in constrDict:
331        # N.B. No "_" names in holds
332        if len(cdict) == 1:
333            fixVlist.append(cdict.keys()[0])
334   
335    # process equivalences: make a list of dependent and independent vars
336    #    and check for repeated uses (repetition of a parameter as an
337    #    independent var is OK)
338    indepVarList = []
339    depVarList = []
340    multdepVarList = []
341    for varlist,mapvars,multarr,invmultarr in zip(
342        dependentParmList,indParmList,arrayList,invarrayList):
343        if multarr is None: # an equivalence
344            zeromult = False
345            for mv in mapvars:
346                varied = 0
347                notvaried = ''
348                if mv in varyList:
349                    varied += 1
350                else:
351                    if notvaried: notvaried += ', '
352                    notvaried += mv
353                if mv not in indepVarList: indepVarList.append(mv)
354                for v,m in zip(varlist,invmultarr):
355                    if m == 0: zeromult = True
356                    if v in varyList:
357                        varied += 1
358                    else:
359                        if notvaried: notvaried += ', '
360                        notvaried += v
361                    if v in depVarList:
362                        multdepVarList.append(v)
363                    else:
364                        depVarList.append(v)
365            if varied > 0 and varied != len(varlist)+1:
366                warnmsg += "\nNot all variables refined in equivalence:\n\t"
367                s = ""
368                for v in varlist:
369                    if s != "": s+= " & "
370                    s += str(v)           
371                warnmsg += str(mv) + " => " + s
372                warnmsg += '\nNot refined: ' + notvaried + '\n'
373            if zeromult:
374                errmsg += "\nZero multiplier is invalid in equivalence:\n\t"
375                s = ""
376                for v in varlist:
377                    if s != "": s+= " & "
378                    s += str(v)           
379                errmsg += str(mv) + " => " + s + '\n'
380
381    # check for errors:
382    if debug:
383        print 'indepVarList',indepVarList
384        print 'depVarList',depVarList
385        print 'multdepVarList',multdepVarList
386    inboth = set(indepVarList).intersection(set(depVarList))
387    if len(inboth) > 0:
388        errmsg += "\nThe following parameters(s) are used as both dependent and independent variables in Equivalence relations:\n"
389        s = ''
390        for var in sorted(inboth):
391            if s != "": s+= ", "
392            s += str(var)
393        errmsg += '\t'+ s + '\n'
394    if len(multdepVarList) > 0:
395        errmsg += "\nThe following parameters(s) are used in multiple Equivalence relations as dependent variables:\n"
396        s = ''
397        for var in sorted(set(multdepVarList)):
398            if s != "": s+= ", "
399            s += str(var)           
400        errmsg += '\t'+ s + '\n'
401    equivVarList = list(set(indepVarList).union(set(depVarList)))
402    if debug: print 'equivVarList',equivVarList
403    inboth = set(fixVlist).intersection(set(equivVarList))
404    if len(inboth) > 0:
405        errmsg += "\nThe following parameter(s) are used in both Equivalence and Fixed constraints:\n"
406        s = ''
407        for var in sorted(inboth):
408            if s != "": s+= ", "
409            s += str(var)
410        errmsg += '\t'+ s + '\n'
411
412    groups,parmlist = GroupConstraints(constrDict)
413    # scan through parameters in each relationship. Are all varied? If only some are
414    # varied, create a warning message.
415    for group,varlist in zip(groups,parmlist):
416        if len(varlist) == 1: continue
417        for rel in group:
418            varied = 0
419            notvaried = ''
420            for var in constrDict[rel]:
421                if var.startswith('_'): continue
422                if not re.match('[0-9]*:[0-9\*]*:',var):
423                    warnmsg += "\nVariable "+str(var)+" does not begin with a ':'"
424                if var in varyList:
425                    varied += 1
426                else:
427                    if notvaried: notvaried += ', '
428                    notvaried += var
429                if var in fixVlist:
430                    errmsg += '\nParameter '+var+" is Fixed and used in a constraint:\n\t"
431                    errmsg += _FormatConstraint(constrDict[rel],fixedList[rel])+"\n"
432            if varied > 0 and varied != len(VarKeys(constrDict[rel])):
433                warnmsg += "\nNot all variables refined in constraint:\n\t"
434                warnmsg += _FormatConstraint(constrDict[rel],fixedList[rel])
435                warnmsg += '\nNot refined: ' + notvaried + '\n'
436    if errmsg or warnmsg:
437        return errmsg,warnmsg
438
439    # now look for process each group and create the relations that are needed to form
440    # non-singular square matrix
441    for group,varlist in zip(groups,parmlist):
442        if len(varlist) == 1: continue # a constraint group with a single variable can be ignored
443        if len(varlist) < len(group): # too many relationships -- no can do
444            errmsg += "\nOver-constrained input. "
445            errmsg += "There are more constraints " + str(len(group))
446            errmsg += "\n\tthan variables " + str(len(varlist)) + "\n"
447            for rel in group:
448                errmsg += _FormatConstraint(constrDict[rel],fixedList[rel])
449                errmsg += "\n"
450                continue
451        try:
452            multarr = _FillArray(group,constrDict,varlist)
453            _RowEchelon(len(group),multarr,varlist)
454        except:
455            errmsg += "\nSingular input. "
456            errmsg += "There are internal inconsistencies in these constraints\n"
457            for rel in group:
458                errmsg += _FormatConstraint(constrDict[rel],fixedList[rel])
459                errmsg += "\n"
460            continue
461        try:
462            multarr = _FillArray(group,constrDict,varlist,FillDiagonals=True)
463            GramSchmidtOrtho(multarr,len(group))
464        except:
465            errmsg += "\nUnexpected singularity with constraints (in Gram-Schmidt)\n"
466            for rel in group:
467                errmsg += _FormatConstraint(constrDict[rel],fixedList[rel])
468                errmsg += "\n"
469            continue
470        mapvar = []
471        group = group[:]
472        # scan through all generated and input variables
473        # Check again for inconsistent variable use
474        # for new variables -- where varied and unvaried parameters get grouped
475        # together. I don't think this can happen when not flagged before, but
476        # it does not hurt to check again.
477        for i in range(len(varlist)):
478            varied = 0
479            notvaried = ''
480            if len(group) > 0:
481                rel = group.pop(0)
482                fixedval = fixedList[rel]
483                for var in VarKeys(constrDict[rel]):
484                    if var in varyList:
485                        varied += 1
486                    else:
487                        if notvaried: notvaried += ', '
488                        notvaried += var
489            else:
490                fixedval = None
491            if fixedval is None:
492                varname = paramPrefix + str(consNum) # assign a name to a variable
493                mapvar.append(varname)
494                consNum += 1
495            else:
496                mapvar.append(fixedval)
497            if varied > 0 and notvaried != '':
498                warnmsg += "\nNot all variables refined in generated constraint"
499                warnmsg += '\nPlease report this unexpected error\n'
500                for rel in group:
501                    warnmsg += _FormatConstraint(constrDict[rel],fixedList[rel])
502                    warnmsg += "\n"
503                warnmsg += '\n\tNot refined: ' + notvaried + '\n'
504        try:
505            np.linalg.inv(multarr)           
506        except:
507            errmsg += "\nSingular input. "
508            errmsg += "The following constraints are not "
509            errmsg += "linearly independent\n\tor do not "
510            errmsg += "allow for generation of a non-singular set\n"
511            errmsg += 'Please report this unexpected error\n'
512            for rel in group:
513                errmsg += _FormatConstraint(constrDict[rel],fixedList[rel])
514                errmsg += "\n"
515    return errmsg,warnmsg
516
517def GenerateConstraints(groups,parmlist,varyList,constrDict,fixedList,parmDict=None,SeqHist=None):
518    '''Takes a list of relationship entries comprising a group of
519    constraints and builds the relationship lists and their inverse
520    and stores them in global variables Also checks for internal
521    conflicts or inconsistencies in parameter/variable definitions.
522
523    :param list groups: a list of grouped contraints where each constraint
524      grouped containts a list of indices for constraint constrDict entries,
525      created in :func:`GroupConstraints` (returned as 1st value)
526
527    :param list parmlist: a list containing lists of parameter names
528      contained in each group, created in :func:`GroupConstraints`
529      (returned as 2nd value)
530
531    :param list varyList: a list of parameters names (strings of form
532      ``<ph>:<hst>:<nam>``) that will be varied. Note that this is changed here.
533   
534    :param dict constrDict: a list of dicts defining relationships/constraints
535      (as defined in :func:`GroupConstraints`)
536
537    :param list fixedList: a list of values specifying a fixed value for each
538      dict in constrDict. Values are either strings that can be converted to
539      floats, float values or None if the constraint defines a new parameter.
540     
541    :param dict parmDict: a dict containing all parameters defined in current
542      refinement.
543
544    :param int SeqHist: number of current histogram, when used in a sequential
545      refinement. None (default) otherwise. Wildcard variable names are
546      set to the current histogram, when found if not None.
547    '''
548    global dependentParmList,arrayList,invarrayList,indParmList,consNum
549    msg = ''
550
551    # process fixed (held) variables
552    for cdict in constrDict:
553        if len(cdict) == 1:
554            fixedVarList.append(cdict.keys()[0])
555   
556    # process equivalences: make a list of dependent and independent vars
557    #    and check for repeated uses (repetition of a parameter as an
558    #    independent var is OK [A=B; A=C], but chaining: [A=B; B=C] is not good)
559    indepVarList = []
560    depVarList = []
561    multdepVarList = []
562    translateTable = {} # lookup table for wildcard referenced variables
563    for varlist,mapvars,multarr,invmultarr in zip(       # process equivalences
564        dependentParmList,indParmList,arrayList,invarrayList):
565        if multarr is None: # true only if an equivalence
566            zeromult = False
567            for mv in mapvars:
568                #s = ''
569                varied = 0
570                notvaried = ''
571                if mv in varyList:
572                    varied += 1
573                else:
574                    if notvaried: notvaried += ', '
575                    notvaried += mv
576                if parmDict is not None and mv not in parmDict:
577                    print "Dropping equivalence for variable "+str(mv)+". Not defined in this refinement"
578                    #msg += "\nCannot equivalence to variable "+str(mv)+". Not defined in this refinement"
579                    #continue
580                else: 
581                    if mv not in indepVarList: indepVarList.append(mv)
582                for v,m in zip(varlist,invmultarr):
583                    if parmDict is not None and v not in parmDict:
584                        print "Dropping equivalence for variable "+str(v)+". Not defined in this refinement"
585                        continue
586                    if m == 0: zeromult = True
587                    if v in varyList:
588                        varied += 1
589                    else:
590                        if notvaried: notvaried += ', '
591                        notvaried += v
592                    if v in depVarList:
593                        multdepVarList.append(v)
594                    else:
595                        depVarList.append(v)
596            if varied > 0 and varied != len(varlist)+1:
597                msg += "\nNot all variables refined in equivalence:\n\t"
598                s = ""
599                for v in varlist:
600                    if s != "": s+= " & "
601                    s += str(v)           
602                msg += str(mv) + " => " + s
603                msg += '\nNot refined: ' + notvaried + '\n'
604            if zeromult:
605                msg += "\nZero multiplier is invalid in equivalence:\n\t"
606                s = ""
607                for v in varlist:
608                    if s != "": s+= " & "
609                    s += str(v)           
610                msg += str(mv) + " => " + s + '\n'
611
612    if debug: print 'indepVarList',indepVarList
613    if debug: print 'depVarList',depVarList
614    # check for errors:
615    inboth = set(indepVarList).intersection(set(depVarList))
616    if len(inboth) > 0:
617        msg += "\nThe following parameters(s) are used as both dependent and independent variables in Equivalence relations:\n"
618        s = ''
619        for var in sorted(inboth):
620            if s != "": s+= ", "
621            s += str(var)
622        msg += '\t'+ s + '\n'
623    if len(multdepVarList) > 0:
624        msg += "\nThe following parameters(s) are used in multiple Equivalence relations as dependent variables:\n"
625        s = ''
626        for var in sorted(set(multdepVarList)):
627            if s != "": s+= ", "
628            s += str(var)           
629        msg += '\t'+ s + '\n'
630    equivVarList = list(set(indepVarList).union(set(depVarList)))
631
632    # scan through parameters in each relationship. Are all varied? If only some are
633    # varied, create an error message.
634    for group,varlist in zip(groups,parmlist):
635        if len(varlist) == 1: continue
636        for rel in group:
637            varied = 0
638            notvaried = ''
639            unused = 0
640            notused = ''
641            for var in constrDict[rel]:
642                if var.startswith('_'): continue
643                if var.split(':')[1] == '*' and SeqHist is not None:
644                    # convert wildcard var to reference current histogram; save translation in table
645                    sv = var.split(':')
646                    sv[1] = str(SeqHist)
647                    translateTable[var] = ':'.join(sv)
648                    var = translateTable[var]
649                if parmDict is not None and var not in parmDict:
650                    unused += 1
651                    if notvaried: notused += ', '
652                    notused += var
653                if var in varyList:
654                    varied += 1
655                else:
656                    if notvaried: notvaried += ', '
657                    notvaried += var
658                if var in fixedVarList:
659                    msg += '\nError: parameter '+var+" is Fixed and used in a constraint:\n\t"
660                    msg += _FormatConstraint(constrDict[rel],fixedList[rel])+"\n"
661            #if unused > 0:# and unused != len(VarKeys(constrDict[rel])):
662            if unused > 0 and unused != len(VarKeys(constrDict[rel])):
663                msg += "\nSome (but not all) variables in constraint are not defined:\n\t"
664                msg += _FormatConstraint(constrDict[rel],fixedList[rel])
665                msg += '\nNot used: ' + notused + '\n'
666            if varied > 0 and varied != len(VarKeys(constrDict[rel])):
667                msg += "\nNot all variables refined in constraint:\n\t"
668                msg += _FormatConstraint(constrDict[rel],fixedList[rel])
669                msg += '\nNot refined: ' + notvaried + '\n'
670    # if there were errors found, go no farther
671    if msg:
672        print ' *** ERROR in constraint definitions! ***'
673        print msg
674        raise Exception
675               
676    # now process each group and create the relations that are needed to form
677    # a non-singular square matrix
678    # If all are varied and this is a constraint equation, then set VaryFree flag
679    # so that the newly created relationships will be varied
680    for group,varlist in zip(groups,parmlist):
681        if len(varlist) == 1: continue
682        # for constraints, if all included variables are refined,
683        # set the VaryFree flag, and remaining degrees of freedom will be
684        # varied (since consistency was checked, if any one variable is
685        # refined, then assume that all are)
686        varsList = [] # make a list of all the referenced variables as well
687        VaryFree = False
688        for rel in group:
689            varied = 0
690            unused = 0
691            for var in VarKeys(constrDict[rel]):
692                var = translateTable.get(var,var) # replace wildcards
693                if parmDict is not None and var not in parmDict:
694                    unused += 1                   
695                if var not in varsList: varsList.append(var)
696                if var in varyList: varied += 1
697            if fixedList[rel] is not None and varied > 0:
698                VaryFree = True
699        if len(varlist) < len(group): # too many relationships -- no can do
700            msg = 'too many relationships'
701            break
702        # Since we checked before, if any variables are unused, then all must be.
703        # If so, this set of relationships can be ignored
704        if unused:
705            if debug: print('Constraint ignored (all variables undefined)')
706            if debug: print ('    '+_FormatConstraint(constrDict[rel],fixedList[rel]))
707            continue
708        # fill in additional degrees of freedom
709        try:
710            arr = _FillArray(group,constrDict,varlist)
711            _RowEchelon(len(group),arr,varlist)
712            constrArr = _FillArray(group,constrDict,varlist,FillDiagonals=True)
713            GramSchmidtOrtho(constrArr,len(group))
714        except:
715            msg = 'Singular relationships'
716            break
717        mapvar = []
718        group = group[:]
719        # scan through all generated and input relationships, we need to add to the varied list
720        # all the new parameters where VaryFree has been set or where a New Var is varied.
721        #
722        # If a group does not contain any fixed values (constraint equations)
723        # and nothing in the group is varied, drop this group, so that the
724        # dependent parameters can be refined individually.
725        unused = True
726        for i in range(len(varlist)):
727            if len(group) > 0: # get the original equation reference
728                rel = group.pop(0)
729                fixedval = fixedList[rel]
730                varyflag = constrDict[rel].get('_vary',False)
731                varname = constrDict[rel].get('_name','')
732            else: # this relationship has been generated
733                varyflag = False
734                varname = ''
735                fixedval = None
736            if fixedval is None: # this is a new variable, not a constraint
737                if not varname:
738                    varname = paramPrefix + str(consNum) # no assigned name, create one
739                    consNum += 1
740                mapvar.append(varname)
741                # vary the new relationship if it is a degree of freedom in
742                # a set of contraint equations or if a New Var is flagged to be varied.
743                if VaryFree or varyflag: 
744                    unused = False
745                    varyList.append(varname)
746                    # fix (prevent varying) of all the variables inside the constraint group
747                    # (dependent vars)
748                    for var in varsList:
749                        if var in varyList: varyList.remove(var)
750            else:
751                unused = False
752                mapvar.append(fixedval)
753        if unused: # skip over constraints that don't matter (w/o fixed value or any refined variables)
754            if debug: print('Constraint ignored (all variables unrefined)')
755            if debug: print ('   '+_FormatConstraint(constrDict[rel],fixedList[rel]))
756            continue 
757        dependentParmList.append([translateTable.get(var,var) for var in varlist])
758        arrayList.append(constrArr)
759        invarrayList.append(np.linalg.inv(constrArr))
760        indParmList.append(mapvar)
761    if msg:
762        print ' *** ERROR in constraint definitions! ***'
763        print msg
764        print VarRemapShow(varyList)
765        raise Exception
766    # setup dictionary containing the fixed values
767    global fixedDict
768    # key is original ascii string, value is float
769    for fixedval in fixedList:
770        if fixedval:
771            fixedDict[fixedval] = float(fixedval)
772
773    if debug: # on debug, show what is parsed & generated, semi-readable
774        print 50*'-'
775        print VarRemapShow(varyList)
776        print 'Varied: ',varyList
777        print 'Not Varied: ',fixedVarList
778
779def StoreEquivalence(independentVar,dependentList):
780    '''Takes a list of dependent parameter(s) and stores their
781    relationship to a single independent parameter (independentVar)
782
783    :param str independentVar: name of master parameter that will be used to determine the value
784      to set the dependent variables
785
786    :param list dependentList: a list of parameters that will set from
787         independentVar. Each item in the list can be a string with the parameter
788         name or a tuple containing a name and multiplier:
789         ``['parm1',('parm2',.5),]``
790
791    '''
792   
793    global dependentParmList,arrayList,invarrayList,indParmList
794    mapList = []
795    multlist = []
796    for var in dependentList:
797        if isinstance(var, basestring):
798            mult = 1.0
799        elif len(var) == 2:
800            var,mult = var
801        else:
802            raise Exception("Cannot parse "+repr(var) + " as var or (var,multiplier)")
803        mapList.append(var)
804        multlist.append(tuple((mult,)))
805    # added relationships to stored values
806    arrayList.append(None)
807    invarrayList.append(np.array(multlist))
808    indParmList.append(tuple((independentVar,)))
809    dependentParmList.append(mapList)
810    return
811
812def GetDependentVars():
813    '''Return a list of dependent variables: e.g. variables that are
814    constrained in terms of other variables
815
816    :returns: a list of variable names
817
818    '''
819    dependentVars = []
820    global dependentParmList
821    for lst in dependentParmList:
822        for itm in lst: dependentVars.append(itm)
823    return dependentVars
824
825def GetIndependentVars():
826    '''Return a list of independent variables: e.g. variables that are
827    created by constraints of other variables
828
829    :returns: a list of variable names
830
831    '''
832    independentVars = []
833    global indParmList,fixedDict
834    for lst in indParmList:
835        for name in lst:
836            if name in fixedDict: continue
837            independentVars.append(name)
838    return independentVars
839
840def PrintIndependentVars(parmDict,varyList,sigDict,PrintAll=False,pFile=None):
841    '''Print the values and uncertainties on the independent variables'''
842    global dependentParmList,arrayList,invarrayList,indParmList,fixedDict
843    printlist = []
844    mapvars = GetIndependentVars()
845    for i,name in enumerate(mapvars):
846        if name in fixedDict: continue
847        if PrintAll or name in varyList:
848            sig = sigDict.get(name)
849            printlist.append([name,parmDict[name],sig])
850    if len(printlist) == 0: return
851    s1 = ''
852    print >>pFile,130*'-'
853    print >>pFile,"Variables generated by constraints"
854    printlist.append(3*[None])
855    for name,val,esd in printlist:
856        if len(s1) > 120 or name is None:
857            print >>pFile,''
858            print >>pFile,s1
859            print >>pFile,s2
860            print >>pFile,s3
861            s1 = ''
862            if name is None: break
863        if s1 == "":
864            s1 = ' name  :'
865            s2 = ' value :'
866            s3 = ' sig   :'
867        s1 += '%15s' % (name)
868        s2 += '%15.4f' % (val)
869        if esd is None:
870            s3 += '%15s' % ('n/a')
871        else:   
872            s3 += '%15.4f' % (esd)
873
874def ComputeDepESD(covMatrix,varyList,parmDict):
875    '''Compute uncertainties for dependent parameters from independent ones
876    returns a dictionary containing the esd values for dependent parameters
877    '''
878    sigmaDict = {}
879    for varlist,mapvars,invmultarr in zip(dependentParmList,indParmList,invarrayList):
880        #if invmultarr is None: continue # probably not needed
881        try: 
882            valuelist = [parmDict[var] for var in mapvars]
883        except KeyError:
884            continue
885        # get the v-covar matrix for independent parameters
886        vcov = np.zeros((len(mapvars),len(mapvars)))
887        for i1,name1 in enumerate(mapvars):
888            if name1 not in varyList: continue
889            iv1 = varyList.index(name1)
890            for i2,name2 in enumerate(mapvars):
891                if name2 not in varyList: continue
892                iv2 = varyList.index(name2)
893                vcov[i1][i2] = covMatrix[iv1][iv2]
894        # vec is the vector that multiplies each of the independent values
895        for v,vec in zip(varlist,invmultarr):
896            sigmaDict[v] = np.sqrt(np.inner(vec.T,np.inner(vcov,vec)))
897    return sigmaDict
898
899def _FormatConstraint(RelDict,RelVal):
900    '''Formats a Constraint or Function for use in a convenient way'''
901    linelen = 45
902    s = [""]
903    for var,val in RelDict.items():
904        if var.startswith('_'): continue
905        if len(s[-1]) > linelen: s.append(' ')
906        m = val
907        if s[-1] != "" and m >= 0:
908            s[-1] += ' + '
909        elif s[-1] != "":
910            s[-1] += ' - '
911            m = abs(m)
912        s[-1] += '%.3f*%s '%(m,var)
913    if len(s[-1]) > linelen: s.append(' ')
914    if RelVal is None:
915        s[-1] += ' = New variable'
916    else:
917        s[-1] += ' = ' + RelVal
918    s1 = ''
919    for s2 in s:
920        if s1 != '': s1 += '\n\t'
921        s1 += s2
922    return s1
923
924def VarRemapShow(varyList):
925    '''List out the saved relationships. This should be done after the constraints have been
926    defined using :func:`StoreEquivalence`, :func:`GroupConstraints` and :func:`GenerateConstraints`.
927
928    :returns: a string containing the details of the contraint relationships
929    '''
930    s = ''
931    if len(fixedVarList) > 0:
932        s += 'Fixed Variables:\n'
933        for v in fixedVarList:
934            s += '    ' + v + '\n'
935    s += 'Variable mapping relations:\n'
936    global dependentParmList,arrayList,invarrayList,indParmList,fixedDict
937    for varlist,mapvars,multarr,invmultarr in zip(
938        dependentParmList,indParmList,arrayList,invarrayList):
939        for i,mv in enumerate(mapvars):
940            if multarr is None:
941                s += '  ' + str(mv) + ' is equivalent to parameter(s): '
942                j = 0
943                for v,m in zip(varlist,invmultarr):
944                    if debug: print 'v,m[0]: ',v,m[0]
945                    if j > 0: s += '  & '
946                    j += 1
947                    s += str(v)
948                    if m != 1:
949                        s += " / " + str(m[0])                       
950                s += '\n'
951                continue
952            s += %s = ' % mv
953            j = 0
954            for m,v in zip(multarr[i,:],varlist):
955                if m == 0: continue
956                if j > 0: s += ' + '
957                j += 1
958                s += '(%s * %s)' % (m,v)
959            if mv in varyList: s += ' VARY'
960            s += '\n'
961    s += 'Inverse variable mapping relations:\n'
962    for varlist,mapvars,invmultarr in zip(dependentParmList,indParmList,invarrayList):
963        for i,mv in enumerate(varlist):
964            s += %s = ' % mv
965            j = 0
966            for m,v in zip(invmultarr[i,:],mapvars):
967                if m == 0: continue
968                if j > 0: s += ' + '
969                j += 1
970                s += '(%s * %s)' % (m,v)
971            s += '\n'
972    return s
973
974def Dict2Deriv(varyList,derivDict,dMdv):
975    '''Compute derivatives for Independent Parameters from the
976    derivatives for the original parameters
977
978    :param list varyList: a list of parameters names that will be varied
979
980    :param dict derivDict: a dict containing derivatives for parameter values keyed by the
981      parameter names.
982
983    :param list dMdv: a Jacobian, as a list of np.array containing derivatives for dependent
984      parameter computed from derivDict
985
986    '''
987    global dependentParmList,arrayList,invarrayList,indParmList,invarrayList
988    for varlist,mapvars,multarr,invmultarr in zip(dependentParmList,indParmList,arrayList,invarrayList):
989        for i,name in enumerate(mapvars):
990            # grouped variables: need to add in the derv. w/r
991            # dependent variables to the independent ones
992            if name not in varyList: continue # skip if independent var not varied
993            if multarr is None:
994                for v,m in zip(varlist,invmultarr):
995                    if debug: print 'start dMdv',dMdv[varyList.index(name)]
996                    if debug: print 'add derv',v,'/',m[0],'to derv',name,'add=',derivDict[v] / m[0]
997                    if m == 0: continue
998                    dMdv[varyList.index(name)] += derivDict[v] / m[0]
999            else:
1000                for v,m in zip(varlist,multarr[i,:]):
1001                    if debug: print 'start dMdv',dMdv[varyList.index(name)]
1002                    if debug: print 'add derv',v,'*',m,'to derv',name,'add=',m * derivDict[v]
1003                    if m == 0: continue
1004                    dMdv[varyList.index(name)] += m * derivDict[v]
1005
1006def Map2Dict(parmDict,varyList):
1007    '''Create (or update) the Independent Parameters from the original
1008    set of Parameters
1009
1010    Removes dependent variables from the varyList
1011
1012    This should be done once, after the constraints have been
1013    defined using :func:`StoreEquivalence`,
1014    :func:`GroupConstraints` and :func:`GenerateConstraints` and
1015    before any variable refinement is done
1016    to complete the parameter dictionary by defining independent
1017    parameters and satisfying the constraint equations.
1018
1019    :param dict parmDict: a dict containing parameter values keyed by the
1020      parameter names.
1021      This will contain updated values for both dependent and independent
1022      parameters after Dict2Map is called. It will also contain some
1023      unexpected entries of every constant value {'0':0.0} & {'1.0':1.0},
1024      which do not cause any problems.
1025
1026    :param list varyList: a list of parameters names that will be varied
1027   
1028
1029    '''
1030    # process the Independent vars: remove dependent ones from varylist
1031    # and then compute values for the Independent ones from their dependents
1032    global dependentParmList,arrayList,invarrayList,indParmList,fixedDict
1033    for varlist,mapvars,multarr in zip(dependentParmList,indParmList,arrayList):
1034        for item in varlist:
1035            try:
1036                varyList.remove(item)
1037            except ValueError:
1038                pass
1039        if multarr is None: continue
1040        valuelist = [parmDict[var] for var in varlist]
1041        parmDict.update(zip(mapvars,
1042                            np.dot(multarr,np.array(valuelist)))
1043                        )
1044    # now remove fixed variables from the varyList
1045    global fixedVarList
1046    for item in fixedVarList:
1047        try:
1048            varyList.remove(item)
1049        except ValueError:
1050            pass
1051    # Set constrained parameters to their fixed values
1052    parmDict.update(fixedDict)
1053
1054def Dict2Map(parmDict,varyList):
1055    '''Applies the constraints defined using :func:`StoreEquivalence`,
1056    :func:`GroupConstraints` and :func:`GenerateConstraints` by changing
1057    values in a dict containing the parameters. This should be
1058    done before the parameters are used for any computations
1059
1060    :param dict parmDict: a dict containing parameter values keyed by the
1061      parameter names.
1062      This will contain updated values for both dependent and independent
1063      parameters after Dict2Map is called. It will also contain some
1064      unexpected entries of every constant value {'0':0.0} & {'1.0':1.0},
1065      which do not cause any problems.
1066
1067    :param list varyList: a list of parameters names that will be varied
1068   
1069    '''
1070    global dependentParmList,arrayList,invarrayList,indParmList,fixedDict
1071    # reset fixed values (should not be needed, but very quick)
1072    # - this seems to update parmDict with {'0':0.0} & {'1.0':1.0} - probably not what was intended
1073    # not needed, but also not a problem - BHT
1074    parmDict.update(fixedDict)
1075    for varlist,mapvars,invmultarr in zip(dependentParmList,indParmList,invarrayList):
1076        #if invmultarr is None: continue
1077        try: 
1078            valuelist = [parmDict[var] for var in mapvars]
1079        except KeyError:
1080            continue
1081        parmDict.update(zip(varlist,
1082                            np.dot(invmultarr,np.array(valuelist)))
1083                        )
1084
1085#======================================================================
1086# internal routines follow (these routines are unlikely to be called
1087# from outside the module)
1088
1089def GramSchmidtOrtho(a,nkeep=0):
1090    '''Use the Gram-Schmidt process (http://en.wikipedia.org/wiki/Gram-Schmidt) to
1091    find orthonormal unit vectors relative to first row.
1092
1093    If nkeep is non-zero, the first nkeep rows in the array are not changed
1094   
1095    input:
1096       arrayin: a 2-D non-singular square array
1097    returns:
1098       a orthonormal set of unit vectors as a square array
1099    '''
1100    def proj(a,b):
1101        'Projection operator'
1102        return a*(np.dot(a,b)/np.dot(a,a))
1103    for j in range(nkeep,len(a)):
1104        for i in range(j):
1105            a[j] -= proj(a[i],a[j])
1106        if np.allclose(np.linalg.norm(a[j]),0.0):
1107            raise Exception,"Singular input to GramSchmidtOrtho"
1108        a[j] /= np.linalg.norm(a[j])
1109    return a
1110
1111def _FillArray(sel,dict,collist,FillDiagonals=False):
1112    '''Construct a n by n matrix (n = len(collist)
1113    filling in the rows using the relationships defined
1114    in the dictionaries selected by sel
1115
1116    If FillDiagonals is True, diagonal elements in the
1117    array are set to 1.0
1118    '''
1119    n = len(collist)
1120    if FillDiagonals:
1121        arr = np.eye(n)
1122    else:
1123        arr = np.zeros(2*[n,])
1124    # fill the top rows
1125    for i,cnum in enumerate(sel):
1126        for j,var in enumerate(collist):
1127            arr[i,j] = dict[cnum].get(var,0)
1128    return arr
1129
1130def _SwapColumns(i,m,v):
1131    '''Swap columns in matrix m as well as the labels in v
1132    so that element (i,i) is replaced by the first non-zero element in row i after that element
1133
1134    Throws an exception if there are no non-zero elements in that row
1135    '''
1136    for j in range(i+1,len(v)):
1137        if not np.allclose(m[i,j],0):
1138            m[:,(i,j)] = m[:,(j,i)]
1139            v[i],v[j] = v[j],v[i]
1140            return
1141    else:
1142        raise Exception,'Singular input'
1143
1144def _RowEchelon(m,arr,collist):
1145    '''Convert the first m rows in Matrix arr to row-echelon form
1146    exchanging columns in the matrix and collist as needed.
1147
1148    throws an exception if the matrix is singular because
1149    the first m rows are not linearly independent
1150    '''
1151    n = len(collist)
1152    for i in range(m):
1153        if np.allclose(arr[i,i],0):
1154            _SwapColumns(i,arr,collist)
1155        arr[i,:] /= arr[i,i] # normalize row
1156        # subtract current row from subsequent rows to set values to left of diagonal to 0
1157        for j in range(i+1,m):
1158            arr[j,:] -= arr[i,:] * arr[j,i]
1159
1160if __name__ == "__main__":
1161    parmdict = {}
1162    constrDict = [
1163        {'0:12:Scale': 2.0, '0:11:Scale': 1.0, '0:14:Scale': 4.0, '0:13:Scale': 3.0, '0:0:Scale': 0.5},
1164        {'0:0:eA': 0.0},
1165        {'2::C(10,6,1)': 1.0, '1::C(10,6,1)': 1.0},
1166        {'1::C(10,0,1)': 1.0, '2::C(10,0,1)': 1.0},
1167        {'1::AUiso:0': 1.0, '0::AUiso:0': 1.0},
1168        {'0::A0': 0.0}
1169        ]
1170    fixedList = ['5.0', '0', None, None, '1.0', '0']
1171    StoreEquivalence('2::atomx:3',('2::atomy:3', ('2::atomz:3',2,), ))
1172    #StoreEquivalence('1::atomx:3',('2::atomx:3', ('2::atomz:3',2,), )) # error: dependent & independent vars mixed
1173    #StoreEquivalence('1::atomx:3',('2::atomy:3', ('2::atomz:3',2,), )) # error: dependent vars repeated
1174    #StoreEquivalence('0:1:eA',('0:0:eA',)) # error: equiv & fixed
1175    #StoreEquivalence('0:99:Scale',('0:12:Scale',)) # error: equiv & constrained
1176    #StoreEquivalence('0:12:Scale',('0:99:Scale',)) # error: equiv & constrained
1177    varylist = ['2::atomx:3',
1178                '2::C(10,6,1)', '1::C(10,6,1)',
1179                '2::atomy:3', '2::atomz:3',
1180                '0:12:Scale', '0:11:Scale', '0:14:Scale', '0:13:Scale', '0:0:Scale']
1181#    e,w = CheckConstraints([,
1182#                     [{'2:0:Scale': 1.0, '5:0:Scale': 1.0, '10:0:Scale': 1.0, '6:0:Scale': 1.0, '9:0:Scale': 1.0, '8:0:Scale': 1.0,# '3:0:Scale': 1.0, '4:0:Scale': 1.0, '7:0:Scale': 1.0, '1:0:Scale': 1.0, '0:0:Scale': 1.0}],
1183#                     ['1.0'])
1184#    if e: print 'error=',e
1185#    if w: print 'error=',w
1186#    varyList = ['0::A0', '0::AUiso:0', '0::Afrac:1', '0::Afrac:2', '0::Afrac:3', '0::Afrac:4', '0::dAx:5', '0::dAy:5', '0::dAz:5', '0::AUiso:5', ':0:Back;0', ':0:Back;1', ':0:Back;2', ':0:Back;3', ':0:Back;4', ':0:Back;5', ':0:Back;6', ':0:Back;7', ':0:Back;8', ':0:Back;9', ':0:Back;10', ':0:Back;11', ':0:U', ':0:V', ':0:W', ':0:X', ':0:Y', ':0:Scale', ':0:DisplaceX', ':0:DisplaceY']
1187#    constrDict = [
1188#        {'0::Afrac:4': 24.0, '0::Afrac:1': 16.0, '0::Afrac:3': 24.0, '0::Afrac:2': 16.0},
1189#        {'0::Afrac:1': 1.0, '0::Afrac:2': 1.0},
1190#        {'0::Afrac:4': 1.0, '0::Afrac:3': 1.0}]
1191#    fixedList = ['40.0', '1.0', '1.0']
1192
1193    errmsg, warnmsg = CheckConstraints(varylist,constrDict,fixedList)
1194    if errmsg:
1195        print "*** Error ********************"
1196        print errmsg
1197    if warnmsg:
1198        print "*** Warning ********************"
1199        print warnmsg
1200    if errmsg or warnmsg:
1201        sys.exit()
1202    groups,parmlist = GroupConstraints(constrDict)
1203    GenerateConstraints(groups,parmlist,varylist,constrDict,fixedList)
1204    print VarRemapShow(varylist)
1205    parmdict.update( {
1206        '0:12:Scale': 1.0, '0:11:Scale': 1.0, '0:14:Scale': 1.0, '0:13:Scale': 1.0, '0:0:Scale': 2.0,
1207        '0:0:eA': 0.0,
1208        '2::C(10,6,1)': 0.2, '1::C(10,6,1)': 0.3,
1209        '1::C(10,0,1)': 0.2, '2::C(10,0,1)': 0.3,
1210        '1::AUiso:0': 0.02, '0::AUiso:0': 0.03,
1211        '0::A0': 0.0,
1212        '2::atomx:3':0.23,'2::atomy:3':-.23, '2::atomz:3':-0.11,
1213        })
1214    print 'parmdict start',parmdict
1215    print 'varylist start',varylist
1216    before = parmdict.copy()
1217    Map2Dict(parmdict,varylist)
1218    print 'parmdict before and after Map2Dict'
1219    print '  key / before / after'
1220    for key in sorted(parmdict.keys()):
1221        print '  '+key,'\t',before.get(key),'\t',parmdict[key]
1222    print 'varylist after',varylist
1223    before = parmdict.copy()
1224    Dict2Map(parmdict,varylist)
1225    print 'after Dict2Map'
1226    print '  key / before / after'
1227    for key in sorted(parmdict.keys()):
1228        print '  '+key,'\t',before.get(key),'\t',parmdict[key]
1229#    dMdv = len(varylist)*[0]
1230#    deriv = {}
1231#    for i,v in enumerate(parmdict.keys()): deriv[v]=i
1232#    Dict2Deriv(varylist,deriv,dMdv)
Note: See TracBrowser for help on using the repository browser.