StollLab / EasySpin

MATLAB toolbox for Electron Paramagnetic Resonance (EPR) spectroscopy
http://easyspin.org
MIT License
48 stars 25 forks source link

Crystal spectra minimum call #322

Closed redman-a closed 4 months ago

redman-a commented 8 months ago

Currently the documentation (crystalsim.html) implies that a crystal simulation can be started from a minimum call just specifying Exp.SampleFrame only and both Exp.CrystalSymmetry and Exp.MolFrame take on default values of 'P1' and [0 0 0], respectively. This is not inline with the current logic in pepper line 400, salt line 244, and saffron line 186 (hash: ecd2425a57b251100408707c63b43f85459eb7c8).

For all (pepper, salt, and saffron) specifying just Exp.SampleFrame returns a powder simulation. For pepper specifying one of Exp.CrystalSymmetry or Exp.MolFrame produces a crystal simulation where the Exp.SampleFrame default [0 0 0] is supplied in resfields. For salt and saffron specifying one of Exp.CrystalSymmetry or Exp.MolFrame returns an error for the incorrectly specified SampleFrame.

Given this behaviour together, I think that it might be more consistent if the logic checks isempty(Exp.SampleFrame), then Exp.CrystalSymmetry and Exp.MolFrame are filled in with defaults, if missing. The check for simultaneuous usage with Exp.Ordering will need to be shifted/adjusted accordingly.

stestoll commented 4 months ago

@redman-a , could you please spell out a code snipped here that shows how you think the logic should be implemented?

redman-a commented 4 months ago

Sorry for not being clear.

I guess it all hangs on what the minimum call should be and if there is a desire to allow Exp.SampleFrame to be used in contexts other than crystals, for example would a user want to be able to use Exp.SampleFrame with a powder or a partially ordered system? If Exp.SampleFrame can only be used with crystals and the documentation is a correct reflection of how it is supposed to work, with regards to default values, then pepper lines 400--411 could become:

if isempty(Exp.SampleFrame) && (~isempty(Exp.CrystalSymmetry) || ~isempty(Exp.MolFrame))
  if ~isempty(Exp.MolFrame)
    error('Exp.MolFrame cannot be used without Exp.SampleFrame.');
  end
  if ~isempty(Exp.CrystalSymmetry)
    error('Exp.CrystalSymmetry cannot be used without Exp.SampleFrame.');
  end
end

PowderSimulation = ~isempty(Exp.Ordering) || isempty(Exp.SampleFrame);
if PowderSimulation
  if ~isempty(Exp.SampleFrame)
    error('Exp.Ordering cannot be used simultaneously with Exp.SampleFrame.');
  end
else
  if isempty(Exp.MolFrame), Exp.MolFrame = [0 0 0]; end
  if isempty(Exp.CrystalSymmetry), Exp.CrystalSymmetry = 'P1'; end
end

There is probably a simpler/more efficient way to pass through this, but hopefully it is clear.

Alternatively, a crystal simulation could force the user to specify all three SampleFrame, CrystalSymmetry, and MolFrame or SampleFrame in combination with one of CrystalSymmetry or MolFrame (in this case perhaps requiring CrystalSymmetry is preferred?). In this case the documentation (crystalsim.html, userguide_pepper.html#crystals, userguide_salt.html#crystals, and userguide_saffron.html#crystals (and perhaps others?)) will need to be updated as well.

stestoll commented 4 months ago

The key decision is indeed what should be the required field(s) to indicate a crystal sample.

Here is one possible logic, where the required field is Exp.MolFrame (not Exp.SampleFrame):

Here is the full list of input possibilities and the proposed behavior:

Exp.Ordering Exp.MolFrame Exp.CrystalSymmetry resulting sample type Exp.SampleFrame
- - - powder disregard
- - + incomplete - error about missing Exp.MolFrame
- + - crystal; supplement Exp.CrystalSymmetry='P1' use; default to [0,0,0]
- + + crystal use; default to [0,0,0]
+ - - partially ordered use; default to [0,0,0]
+ - + contradictory - error
+ + - contradictory - error
+ + + contradictory - error

Note that the variable PowderSimulation in pepper currently includes both powders and partially ordered samples (since both require integration over all orientations).

Here is a possible implementation of the above logic:

% Detect sample type (disordered, partially ordered, crystal)
partiallyOrderedSample = ~isempty(Exp.Ordering);
disorderedSample = ~partiallyOrderedSample && isempty(Exp.MolFrame);
crystalSample = ~partiallyOrderedSample && ~isempty(Exp.MolFrame);
if partiallyOrderedSample && ~isempty(Exp.MolFrame)
    error('Exp.MolFrame cannot be used for partially ordered samples (Exp.Ordering).');
end
if partiallyOrderedSample && ~isempty(Exp.CrystalSymmetry)
  error('Exp.CrystalSymmetry cannot be used for partially ordered samples (Exp.Ordering).');
end
if disorderedSample && ~isempty(Exp.CrystalSymmetry)
  error('For crystals, provide Exp.MolFrame in addition to Exp.CrystalSymmetry.');
end
if ~disorderedSample && isempty(Exp.SampleFrame)
  Exp.SampleFrame = [0 0 0];
end
if crystalSample && isempty(Exp.CrystalSymmetry)
  Exp.CrystalSymmetry = 'P1';
end
PowderSimulation = disorderedSample || partiallyOrderedSample;
Exp.PowderSimulation = PowderSimulation;

Does this look reasonable? Are there better alternatives?

stestoll commented 4 months ago

Pondering this a bit more, I think that requiring Exp.CrystalSymmetry for a minimum input for specifying a crystal is the most explicit and convenient. Exp.MolFrame and Exp.SampleFrame can both default to [0 0 0] if missing. I also would rename Exp.CrystalSymmtry to Exp.Crystal. Examples:

Exp.Crystal = 'P1';   % crystal; space group provided
Exp.Crystal = 131;    % crystal; space group provided
Exp.Crystal = true;   % crystal, uses space group #1 (P1) 

Exp.Crystal = [];     % powder
Exp.Crystal = '';     % powder
Exp.Crystal = false;  % powder

Alternatives:

cetait commented 4 months ago

I think I would consider two different things, for actual crystal simulations, having to specify only the crystal symmetry, and Exp.MolFrame and Exp.SampleFrame defaulting to [0 0 0] does make sense. However, I think it would also be convenient to be able to get a single orientation simulation by specifying Exp.MolFrame only, in cases where someone wants to see what a spectrum for a single orientation of the molecule/the contribution of a specific orientation of a molecule to the spectrum would look like without having to think about crystal symmetries.

I would be in favor of Exp.SampleFrame not being a requirement and just assumed to be [0 0 0] in general, unless users explicitly define this if they want to use this feature.

If the distinction between different samples is crystal/partially ordered sample/disordered (powder) sample, would an Exp.Crystal field with true/false be clean and general enough, or would it then be better to have a field that would cover ordering as well (crystal - single/set of distinct orientations, partially ordered - continuous weighted distribution of orientations, powder - all orientations)? I'm not sure whether it wouldn't be best to keep Exp.CrystalSymmetry, since a combination of that and Exp.MolFrame is needed to get the information on what orientations need to be considered in the crystal simulation, whereas a single field (Exp.Ordering) is enough to describe the weighted distribution of orientations in a partially ordered sample.

redman-a commented 4 months ago

I think my previous suggestions are the least desirable/suitable and think Exp.SampleFrame being not a requirement is the most logical. For a crystal simulation Exp.CrystalSymmetry seems the most straightforward. Although I have had cases that fit in with Claudia's single orientation comment and agree that a concise way to extract single orientations, where considering a single orientation as a crystal might not be obvious, might be convenient.

I'm not sure what the change to Crystal and the true/false options add, does true mask the symmetry and potentially lead to confusion and would the false option be hardly used (presumably people wanting a powder simulation would not be forced to declare false)? If someone had Exp.Crystal = false and supplied an Exp.MolFrame what would happen? Does a user need to explicitly specify the sample types or can this just be inferred from the input.

stestoll commented 4 months ago

Thanks for the input. To summarize:

  1. Exp.Ordering is given -> partially ordered
  2. Exp.MolFrame or Exp.CrystalSymmetry or both given -> crystal
  3. Exp.SampleFrame is optional for all sample types