status: potential surface scanning
Dear friends, just a small update for the potential scanning stuff: It works fine for one shell. Really straightforward thanks to the ifeffit() calls. Some corrections and I can provide you the program ;) But there is one little thing I am thinking about, which is fairly general, I think: If I just have one shell, everything is fine. The program iterates through all possible variable combinations. But... if I have two shells I just manage to let him vary the shells independently. I know there must be a way to tell the algorithm that if there are 2 shells it needs to vary each of the eight parameters against each other and not two times the four from each shell. I know there are some good PERL hackers around. So do you have an idea how to do this? Recursion shurely helps - I experimented a lot with it but it still does not do what I need it to do. Just for your convenience: I stored the parameters in an array of hashes, so that I can have something like $shell[0]{E0} = $something $shell[0]{dr} = $somethingelse... So the loop for one shell is just looping through the hashkeys of element 0 of this array... Thanks for your suggestions. Cheers, Norbert -- Dr. rer. nat. Norbert Weiher (norbertweiher@yahoo.de) Laboratory for Technical Chemistry - ETH Hönggerberg HCI E 117 - 8093 Zürich - Phone: +41 1 63 3 48 32
On Monday 28 July 2003 10:48 am, Norbert Weiher wrote:
I know there are some good PERL hackers around. So do you have an idea how to do this? Recursion shurely helps - I experimented a lot with it but it still does not do what I need it to do. Just for your convenience: I stored the parameters in an array of hashes, so that I can have something like
$shell[0]{E0} = $something $shell[0]{dr} = $somethingelse...
So the loop for one shell is just looping through the hashkeys of element 0 of this array...
Hi Norbert, I am not certain that I understand the problem as you explained it, but it seems that what you need to do is to harvest the entire list of parameters that need to be varied from the array of hashes. Your data structure (the AoH) is an excellent one for storing the data, but isn't the right one for exploring the surface. Probably there is no single data structure that will do everything you want, so you end up needing to spend time shuffling data between different structures. Initially define @shell as a zero-length array like so: my @shell = (); Perl will autovivify new array elements as needed. Thus, for a one shell fit, you will do $shell[0]{e0} = $parameter_1; $shell[0]{delr} = $parameter_2; ## and so on... When and if you need a second shell, the next array element will spring into existance whenever you do something like this: $shell[1]{e0} = $parameter_N; and will *not* spring into existence *unless* you do something like that. To get a list of all the parameters, try this: my @parameter_list = (); foreach my $i (0 .. $#shells) { foreach my $k (keys %{$shell[$i]}) { push @parameter_list, $shell[$i]{$k}; }; }; This little idiom will fill @parameter_list with all the parameters with no prior knowledge of how many shells you actually defined. Indeed, you can add such things as the third cumulant and Ei to the fit without fretting that @parameter_list will miss them. You can also do clever things like checking $shell[$i]{$k} against the current contents of @parameter_list. This will allow you to use the same parameter for, say, e0 for each path without varying it against itself when you go to measure the surface. (Use recipe 4.6 in "The Perl Cookbook" by Christiansen and Torkington -- highly recommended if you do not already have a copy. I usually use the solution labeled "faster but different".) HTH, B P.S. The object oriented programming purist would insist that you should create an object based on your array of hashes and define a method to return the list of parameters. That's not wrong and it's highly reusable, but it may be overkill for your current project. In any case, all the method would do is shuffle data between data structures using nested foreach loops. -- Bruce Ravel ----------------------------------- ravel@phys.washington.edu Code 6134, Building 3, Room 222 Naval Research Laboratory phone: (1) 202 767 5947 Washington DC 20375, USA fax: (1) 202 767 1697 NRL Synchrotron Radiation Consortium (NRL-SRC) Beamlines X11a, X11b, X23b, X24c, U4b National Synchrotron Light Source Brookhaven National Laboratory, Upton, NY 11973 My homepage: http://feff.phys.washington.edu/~ravel EXAFS software: http://feff.phys.washington.edu/~ravel/software/exafs/
Hi Norbert,
If I just have one shell, everything is fine. The program iterates through all possible variable combinations.
But...
if I have two shells I just manage to let him vary the shells independently. I know there must be a way to tell the algorithm that if there are 2 shells it needs to vary each of the eight parameters against each other and not two times the four from each shell.
Maybe I'm missing something, but why not just iterate through all pairs of variables, and not worry about assigning them to a particular shell? for all variables: adjust value for all other variables: adjust value run ff2chi(), etc. to generate model xafs spectra calculate goodness-of-fit with data store in chisquare(variable1,variable2) I thought that's what you were doing.
I know there are some good PERL hackers around. So do you have an idea how to do this? Recursion shurely helps - I experimented a lot with it but it still does not do what I need it to do. Just for your convenience: I stored the parameters in an array of hashes, so that I can have something like
$shell[0]{E0} = $something $shell[0]{dr} = $somethingelse...
So the loop for one shell is just looping through the hashkeys of element 0 of this array...
I'd think of variables as different from the formal path parameters, so that $shell[0]{E0} = $variables{'e0'}; $shell[0]{dr} = $variables{'dr0'}; and the perl %variable hash mapped perl names to Ifeffit variable names. Maybe you'd want a variable structure that contained 'perl name', 'Ifeffit variable name', and 'value' for each variable, and a path parameter structure that contained 'definition' and 'value'. These structures could definitely be classes. Another potential thing to try is to use perl's Tie mechanism to make a setting/retrieving a perl variable automatically set/get an Ifeffit program variable. That could simplify the process of iterating over variables in perl and having the right Ifeffit variable get automatically updated. At least something like $variable{'e0'} = 1.0 ; could replace $variable{'e0'}['value'] = 1.0 ; Ifeffit:put_scalar($variable{'e0'}['iff_name'],$variable{'e0'}['value']}; (don't trust my perl syntax!!!). That's closely associated with having a 'Ifeffit_variable' class, but that might be the right thing for this job (and others). I think that would not be too difficult to do, and would be a generally useful addition to Ifeffit.pm. Hope that helps, --Matt
participants (3)
-
Bruce Ravel
-
Matt Newville
-
Norbert Weiher