Hi Matt,
In a simplified case, you'd like to constrain two coordination numbers to be positive _and_ to add up to some value, right? guess n1_var = 5 def n1 = abs(n1_var) def n2 = 12 - n1
or, if you're worried about n1 > 12, n2<0, you could do: guess n1_var = 5 def n1 = max(0,min(n1_var,12)) def n2 = 12 - n1
Is that good enough, or am I not seeing the whole complicated picture?
That's a very good (less complicated) example of what I'm thinking of. In the example you just gave, you have to guarantee that n2 is positive by putting limits on n1. Suppose we make it just slightly more complicated, with three coordination numbers that have to be positive and add up to some value. I guess it could be done this way: guess n1_var = 5 def n1 = max(0,min(n1_var,12)) guess n2_var = 5 def n2 = max(0,min(n2_var,12-n1)) def n3 = 12 - n1 - n2 So that strategy might work. It might get very complicated, though; we have something like six constrained sums with variables often appearing in more than one sum. For example, the fraction of copper atoms in nominally copper sites appears in the sum requiring the total amount of copper to match the stoichiometry, and in the sum requiring the total number of atoms + vacancies in nominally copper sites to match the number of copper sites. We'll look at it, but I think it may be very unwieldy. Your next suggestion, though, should do it:
I think this is possible without a change to the code. You can add a restraint penalty when some value is outside a range [lo_val,hi_val]. It's a bit scary looking, but this will do it:
lo_val = 0.7 ## lower bound up_val = 1.0 ## upper bound scale = 1.000 ## scale can be increased to weight this restraint target = 0.8 ## this could be a variable, say S02
## use penalty as a restraint in feffit() def penalty = (max((target-lo_val), abs(target-lo_val)) - min((target-up_val),-abs(target-up_val)) + lo_val - up_val)*scale
This penalty can be used as a restraint, and will be 0 when the target value is between the lower and upper bound.
To set a penalty only for going below the lower bound, it's just def penalty = max((target-lo_val),abs(target-lo_val))-(target- lo_val)
and if the lower bound is 0, it's even simpler: def penalty = max(target,abs(target))-target
Yes! Very clever. I've used a similar strategy to implement "if-then-else" type assignments. This seems considerably easier to implement in complicated situations than the previous method.
Even that is scary enough, and the whole thing may suggest a change to the code to make a simple function that provides a restraint penalty when a variable is outside some user-selected bounds, perhaps as bound(x, lo_val, hi_val) # not implemented!
Is this way of setting a penalty what you had in mind, or am I missing the point?
Yes, that's exactly what I had in mind. I would certainly find it very useful...this isn't the first system I've analyzed where it would have helped, although I've usually been able to get around it with judicious use of abs() or max/min. I am curious if others would find this feature helpful. Now that you've pointed out how to do the same thing with the current restraints, I don't really need the shortcut...you've seen enough of my fits to know I don't shy away from long expressions. :) But of course it would make life easier. --Scott Calvin Sarah Lawrence College