In this example, a series of silver/gold alloys are co-refined using a simple model in which the first shell is a mixture of silver and gold backscatterers in the same proportion as the bulk. This example lends itself quite naturally to using the characteristic value of the Data object. It also demonstrates a direct manipulation of a Feff object without editing a feff.inp file.
- #!/usr/bin/perl use Demeter qw(:ui=screen :plotwith=gnuplot);
- print "Multiple data set fit to several AgAu samples using Demeter $Demeter::VERSION\n";
- ### -------- import five sets of Ag and Ag/Au data from an Athena project file my $prj = Demeter::Data::Prj->new(file => 'AgAu_merged.prj');
- $prj -> set_mode(screen=>0, backend=>1);
- my @common = (fft_kmin => 2, fft_kmax => 11,
- bft_rmax => 3.2, bft_rmin => 1.8,
- fit_k1 => 1, fit_k2 => 0, fit_k3 => 1,);
- my $data_100 = $prj->record(1);
- $data_100 -> set(@common, cv => 1, name => 'pure silver');
- my $data_80 = $prj->record(3);
- $data_80 -> set(@common, cv => 0.8, name => '80% silver');
- my $data_60 = $prj->record(5);
- $data_60 -> set(@common, cv => 0.6, name => '60% silver');
- my $data_50 = $prj->record(6);
- $data_50 -> set(@common, cv => 0.5, name => '50% silver');
- my $data_40 = $prj->record(7);
- $data_40 -> set(@common, cv => 0.4, name => '40% silver');
- ## -------- make GDS objects for an isotropic expansion, correlated
- ## Debye, mixed first shell fit to silver and silver/gold
my @gdsobjects = ($data_100 -> simpleGDS("guess amp = 1"),- $data_100 -> simpleGDS("guess enot = 0"),
- $data_100 -> simpleGDS("guess dr_ag = 0"),
- $data_100 -> simpleGDS("guess ss_ag = 0.003"),
- $data_100 -> simpleGDS("guess dr_au = 0"),
- $data_100 -> simpleGDS("guess ss_au = 0.003"),
- ## Determine Ag::Au ratios with an lguess
- ## $data_100 -> simpleGDS("lguess frac = 0.6"),
);- ## -------- import Ag crystal data and generate a feff.inp file my $atoms = Demeter::Atoms->new(file => "Ag.inp");
- open(my $FEFF, '>feff.inp');
- print $FEFF $atoms->Write("feff6");
- close $FEFF;
- ## -------- run Feff on pure silver my $agfeff = Demeter::Feff -> new(file => "feff.inp");
- $agfeff -> set(workspace=>"feff/", screen=>0,);
- $agfeff -> make_workspace;
- $agfeff -> run;
- ## -------- make a path object from the 1st shell of pure silver, use
- ## this for the pure silver data
my @paths = ();- $paths[0] = Demeter::Path -> new();
- $paths[0]->set(data => $data_100,
- parent => $agfeff,
- sp => $agfeff->pathlist->[0],
- name => 'silver',
- n => 12,
- s02 => 'amp',
- e0 => 'enot',
- delr => 'dr_ag',
- sigma2 => 'ss_ag',
- );
- ## -------- clone the Ag Feff calculation, add Au to the potentials
- ## list, make an Au scatterer out of the first site after the
- ## absorber
my $aufeff = $agfeff->Clone;- $aufeff -> set(workspace=>"feffau/", screen=>0,);
- $aufeff -> make_workspace;
- $aufeff -> push_potentials([2, 79, 'Au']); ## add Au to the end of the potentials list
- my @sites = @{ $aufeff->sites }; ## make the first atom after the
- my @neighbor = @{ $sites[1] }; ## absorber in the sites list an Au
- @neighbor[3,4] = (2,'Au'); ## (this could be easier...)
- $sites[1] = \@neighbor;
- $aufeff -> sites(\@sites);
- $aufeff -> run; ## and continue
- ## -------- clone the Path object several times, taking care to
- ## correctly map paths to data sets
my %map = (2=>$data_80, 4=>$data_60, 6=>$data_50, 8=>$data_40);- my %percentage = (2=>'80', 4=>'60', 6=>'50', 8=>'40');
- foreach my $i (2,4,6,8) { # clone silver paths
- my $j = $i-1;
- $paths[$j] = $paths[0]->Clone(data => $map{$i},
- #s02 => "amp*frac", # lguess s02 => "amp*[cv]", # char. value
- );
- };
- foreach my $i (2,4,6,8) { # clone gold paths
- my $j = $i-1;
- $paths[$i] = $paths[$j]->Clone(parent => $aufeff,
- sp => $aufeff->find_path(tag=>['Au']),
- name => "gold",
- n => 12,
- #s02 => "amp*(1-frac)", # lguess s02 => "amp*(1-[cv])", # char. value
- delr => "dr_au",
- sigma2 => "ss_au",
- );
- };
- ## -------- make a Fit object, which is just a collection of GDS, Data, and Path objects my $fitobject = Demeter::Fit -> new;
- $fitobject->set(gds => \@gdsobjects,
- data => [$data_100, $data_80, $data_60, $data_50, $data_40],
- paths => \@paths
- );
- ## -------- do the fit $fitobject -> fit;
- $fitobject -> interview;
An ATHENA project file is imported at line 6. At lines 11 through 24, five of the data sets from the project file are imported into Data objects. Each one has its name cv attributes set appropriately. The cv is set to the bulk fradction of silver in the sample.
A set of guess parameters is defined at lines 28-33 for a simple fitting model that includes overall amplitude and E₀ parameters along with ΔR and σ² parameters for each type of scatterer.
At line 39-42 an atoms.inp is imported and a temporary feff.inp is written. This feff.inp is imported, forming a Feff object at line 45. Note that the run method at line 48 is a wrapper around the potph and pathfinder methods. The first path from this calculation, the one corresponding to the 12 silver atoms in the first coordination shell, is made into a Path object at lines 53-63. Note the idiomatic dereferencing of the first ScatteringPath object from the FEFF calculation at line 56. Note that this Path object points at the Data object for the pure silver data.
The FEFF calculation for the contribution from the Au scatterer is obtained at lines 68-77. Here's how it works. First, the Feff object from the pure silver calculation is cloned at line 68 and a separate workspace is established at lines 69 and 70. At line 71, a new potential type is pushed onto the list of potentials of the cloned Feff object. At lines 72-76, an atom from the first coordination shell is switched from silver to gold. This modified sites list is then pushed back into the object.
The manipulations at lines 68-77 represent both a weakness and a great strength of DEMETER's interactions with FEFF. On one hand, DEMETER currently lacks more graceful tools for making these manipulations. On the other hand, this example demonstrates the extent to which a FEFF calculation can be controlled algorithmically. Thus complex modeling chores can be programed directly rather than prepared on disk beforehand.
At lines 81-101, paths are set up for the four alloy samples. First, at 83-89, the silver path is cloned and assigned to each alloy Data object. Note that the characteristic value is used to get the amplitude term set correctly for each alloy Data object. In this case, the cv is set to the amount of silver in each sample. When the [cv] token is resolved, each silver path will have its amplitude set properly.
At lines 90-101, more paths are cloned, then modified to use the ScatteringPath object which corresponds to the gold scatterer from the second FEFF calculation. Again, care is taken to make sure that the correct Path object, with the correct cv value, is associated with the correct Data object. Note the use of the find_path method at line 93. This identifies the ScatteringPath object using a semantic path description. This simplifies the chore of finding the correct ScatteringPath without needing to keep track of the order of scattering paths in the FEFF calculation.
Finally, the Fit object is created and the fit is run. Finally, the interview method is called so the fit can be examined interactively from a command line script.
As a final note, the fit presented here assumes that the mixture of silver and gold in the first coordination shell is of the same ratio as the nominal bulk mixing ratios. This assumption can be easily relaxed. By uncommenting lines 35, 86, and 96 and commenting out line 87 and 97, the fixed mixing ratios are turned into a guess parameter for each data set using a local guess parameter. In this way, the lguess is expanded into 5 guess parameters, one for each data set. Try it!