// Reads a POSCAR or layers.yaml into an intermediate form which can have its
// parameters optimized before producing a structure. (it also returns some other
// layer-related data).
//
// Be aware that layers.yaml files usually *require* optimization.
//
// A POSCAR will have its layers searched if the relevant config section is provided.
Reads a POSCAR or layers.yaml into an intermediate form which can have its
parameters optimized before producing a structure. (it also returns some other
layer-related data).

Be aware that layers.yaml files usually *require* optimization.

A POSCAR will have its layers searched if the relevant config section is provided.
Reads a POSCAR or layers . yaml into an intermediate form which can have its parameters optimized before producing a structure . ( it also returns some other layer - related data ) . Be aware that layers . yaml files usually * require * optimization . A POSCAR will have its layers searched if the relevant config section is provided .
pub(crate) fn read_optimizable_structure(
    layer_cfg: Option<&cfg::LayerSearch>,
    mass_cfg: Option<&cfg::Masses>,
    file_format: StructureFileType,
    input: impl AsPath,
) -> FailResult<(
    // FIXME train wreck output
    // TODO could contain bonds read from .structure
    ScalableCoords,
    HList5<
        meta::SiteElements,
        meta::SiteMasses,
        Option<meta::SiteLayers>,
        Option<meta::LayerScMatrices>,
        Option<meta::FracBonds>,
    >,
)> {
    use crate::meta::Layer;
    let input = input.as_path();
    let out_coords: ScalableCoords;
    let out_elements: meta::SiteElements;
    let out_masses: meta::SiteMasses;
    let out_layers: Option<meta::SiteLayers>;
    let out_sc_mats: Option<meta::LayerScMatrices>;
    let out_bonds: Option<meta::FracBonds>;
    match file_format {
        StructureFileType::Xyz => {
            use rsp2_structure_io::Xyz;
            let Xyz { carts, elements, .. } = Load::load(input.as_path())?;
            out_elements = elements.into();
            out_masses = masses_by_config(mass_cfg, out_elements.clone())?;
            let vacuum_sep = 30.0;
            let coords = Coords::from_molecule(&carts, vacuum_sep);
            if let Some(cfg) = layer_cfg {
                let layers = perform_layer_search(cfg, &coords)?;
                // Technically no scaling should ever be needed for XYZ files,
                // but this is the type we return...
                out_coords = ScalableCoords::from_layer_search_results(coords, cfg, &layers);
                out_layers = Some(layers.by_atom().into_iter().map(Layer).collect::<Vec<_>>().into());
                // XYZ is not periodic
                out_sc_mats = None;
            } else {
                out_coords = ScalableCoords::from_unlayered(coords);
                out_layers = None;
                out_sc_mats = None;
            }
            out_bonds = None;
        },
        StructureFileType::Poscar => {
            use rsp2_structure_io::Poscar;
            let Poscar { coords, elements, .. } = Load::load(input.as_path())?;
            out_elements = elements.into();
            out_masses = masses_by_config(mass_cfg, out_elements.clone())?;
            if let Some(cfg) = layer_cfg {
                let layers = perform_layer_search(cfg, &coords)?;
                out_coords = ScalableCoords::from_layer_search_results(coords, cfg, &layers);
                out_layers = Some(layers.by_atom().into_iter().map(Layer).collect::<Vec<_>>().into());
                // We could do a primitive cell search, but anything using our results would have
                //  trouble interpreting our results if we chose a different cell from expected.
                // Thus, anything using sc matrices requires them to be supplied in advance.
                out_sc_mats = None;
            } else {
                out_coords = ScalableCoords::from_unlayered(coords);
                out_layers = None;
                out_sc_mats = None;
            }
            out_bonds = None;
        },
        StructureFileType::LayersYaml => {
            use rsp2_structure_io::layers_yaml::load;
            use rsp2_structure_io::layers_yaml::load_layer_sc_info;
            let layer_builder = load(FileRead::open(input)?)?;
            out_sc_mats = Some({
                load_layer_sc_info(FileRead::open(input)?)?
                    .into_iter()
                    .map(|(matrix, periods, _)| ScMatrix::new(&matrix, &periods))
                    .collect_vec()
                    .into()
            });
            out_layers = Some(layer_builder.atom_layers().into_iter().map(Layer).collect::<Vec<_>>().into());
            out_elements = vec![CARBON; layer_builder.num_atoms()].into();
            out_masses = masses_by_config(mass_cfg, out_elements.clone())?;
            out_coords = ScalableCoords::KnownLayers { layer_builder };
            out_bonds = None; // Determine bonds AFTER parameter optimization.
            if let Some(_) = layer_cfg {
                trace!("{} is in layers.yaml format, so layer-search config is ignored", input.nice())
            }
        },
        StructureFileType::StoredStructure => {
            let StoredStructure {
                coords, elements, layers, masses, layer_sc_matrices, frac_bonds, ..
            } = Load::load(input.as_path())?;
            out_elements = elements;
            out_layers = layers;
            out_masses = masses;
            out_sc_mats = layer_sc_matrices;
            out_bonds = frac_bonds;
            // (FIXME: just having the layer indices metadata isn't good enough; we need
            //         to be able to get contiguous layers, e.g. using rsp2_structure::Layers.
            //
            //         That said, I don't see any good reason to be optimizing layer seps
            //         on structures read in this format)
            out_coords = ScalableCoords::from_unlayered(coords);
            if let Some(_) = mass_cfg {
                trace!("{} is in directory format, so mass config is ignored", input.nice())
            }
            if let Some(_) = layer_cfg {
                trace!("{} is in directory format, so layer-search config is ignored", input.nice())
            }
        },
    }
    Ok((out_coords, hlist![out_elements, out_masses, out_layers, out_sc_mats, out_bonds]))
}
pub ( crate ) fn read_optimizable_structure ( layer_cfg : Option < & cfg :: LayerSearch > , mass_cfg : Option < & cfg :: Masses > , file_format : StructureFileType , input : impl AsPath , ) -> FailResult < ( // FIXME train wreck output // TODO could contain bonds read from .structure ScalableCoords , HList5 < meta :: SiteElements , meta :: SiteMasses , Option < meta :: SiteLayers > , Option < meta :: LayerScMatrices > , Option < meta :: FracBonds > , > , ) > { use crate :: meta :: Layer ; let input = input . as_path ( ) ; let out_coords : ScalableCoords ; let out_elements : meta :: SiteElements ; let out_masses : meta :: SiteMasses ; let out_layers : Option < meta :: SiteLayers > ; let out_sc_mats : Option < meta :: LayerScMatrices > ; let out_bonds : Option < meta :: FracBonds > ; match file_format { StructureFileType :: Xyz => { use rsp2_structure_io :: Xyz ; let Xyz { carts , elements , .. } = Load :: load ( input . as_path ( ) ) ? ; out_elements = elements . into ( ) ; out_masses = masses_by_config ( mass_cfg , out_elements . clone ( ) ) ? ; let vacuum_sep = 30.0 ; let coords = Coords :: from_molecule ( & carts , vacuum_sep ) ; if let Some ( cfg ) = layer_cfg { let layers = perform_layer_search ( cfg , & coords ) ? ; // Technically no scaling should ever be needed for XYZ files, // but this is the type we return... out_coords = ScalableCoords :: from_layer_search_results ( coords , cfg , & layers ) ; out_layers = Some ( layers . by_atom ( ) . into_iter ( ) . map ( Layer ) . collect :: < Vec < _ > > ( ) . into ( ) ) ; // XYZ is not periodic out_sc_mats = None ; } else { out_coords = ScalableCoords :: from_unlayered ( coords ) ; out_layers = None ; out_sc_mats = None ; } out_bonds = None ; } , StructureFileType :: Poscar => { use rsp2_structure_io :: Poscar ; let Poscar { coords , elements , .. } = Load :: load ( input . as_path ( ) ) ? ; out_elements = elements . into ( ) ; out_masses = masses_by_config ( mass_cfg , out_elements . clone ( ) ) ? ; if let Some ( cfg ) = layer_cfg { let layers = perform_layer_search ( cfg , & coords ) ? ; out_coords = ScalableCoords :: from_layer_search_results ( coords , cfg , & layers ) ; out_layers = Some ( layers . by_atom ( ) . into_iter ( ) . map ( Layer ) . collect :: < Vec < _ > > ( ) . into ( ) ) ; // We could do a primitive cell search, but anything using our results would have //  trouble interpreting our results if we chose a different cell from expected. // Thus, anything using sc matrices requires them to be supplied in advance. out_sc_mats = None ; } else { out_coords = ScalableCoords :: from_unlayered ( coords ) ; out_layers = None ; out_sc_mats = None ; } out_bonds = None ; } , StructureFileType :: LayersYaml => { use rsp2_structure_io :: layers_yaml :: load ; use rsp2_structure_io :: layers_yaml :: load_layer_sc_info ; let layer_builder = load ( FileRead :: open ( input ) ? ) ? ; out_sc_mats = Some ( { load_layer_sc_info ( FileRead :: open ( input ) ? ) ? . into_iter ( ) . map ( | ( matrix , periods , _ ) | ScMatrix :: new ( & matrix , & periods ) ) . collect_vec ( ) . into ( ) } ) ; out_layers = Some ( layer_builder . atom_layers ( ) . into_iter ( ) . map ( Layer ) . collect :: < Vec < _ > > ( ) . into ( ) ) ; out_elements = vec ! [ CARBON layer_builder num_atoms ( ) ] . into ( ) ; out_masses = masses_by_config ( mass_cfg , out_elements . clone ( ) ) ? ; out_coords = ScalableCoords :: KnownLayers { layer_builder } ; out_bonds = None ; // Determine bonds AFTER parameter optimization. if let Some ( _ ) = layer_cfg { trace ! ( " " input nice ( ) ) } } , StructureFileType :: StoredStructure => { let StoredStructure { coords , elements , layers , masses , layer_sc_matrices , frac_bonds , .. } = Load :: load ( input . as_path ( ) ) ? ; out_elements = elements ; out_layers = layers ; out_masses = masses ; out_sc_mats = layer_sc_matrices ; out_bonds = frac_bonds ; // (FIXME: just having the layer indices metadata isn't good enough; we need //         to be able to get contiguous layers, e.g. using rsp2_structure::Layers. // //         That said, I don't see any good reason to be optimizing layer seps //         on structures read in this format) out_coords = ScalableCoords :: from_unlayered ( coords ) ; if let Some ( _ ) = mass_cfg { trace ! ( " " input nice ( ) ) } if let Some ( _ ) = layer_cfg { trace ! ( " " input nice ( ) ) } } , } Ok ( ( out_coords , hlist ! [ out_elements out_masses out_layers out_sc_mats out_bonds ] ) ) }
Reads a POSCAR or layers.yaml into an intermediate form which can have its
parameters optimized before producing a structure.
Reads a POSCAR or layers . yaml into an intermediate form which can have its parameters optimized before producing a structure .
layer_cfg
Option<&cfg::LayerSearch>
mass_cfg
Option<&cfg::Masses>
file_format
StructureFileType
input
impl AsPath