Skip to content

Full Example Script

Uninterrupted code extracted from the code example.

def main():
    from FoSpy import (
        Synthesis, FileBlock,
        blocks as fb
    )
    # for Material blocks use fb.Material
    from chemformula import ChemFormula


    # No debug messages by default, but they can be turned on like this.
    from FoSpy._debug import all_debugs_on, all_debugs_off
    all_debugs_on(soundoff=False)

    # Change the width of your debug screen so that module labels print on one line.
    from FoSpy import _debug as db
    db.DEBUG_WIDTH = 120

    # Optional way to turn on/off one module's debug messages.
    from FoSpy.blocks.blocks import _debug as block_debug
    block_debug.on = True



    # load synthesis and templates from files
    my_synthesis = Synthesis.fromFile(r"synthesis/start_synthesis.fos")
    my_templates = FileBlock.fromFile(r"templates/start_templates.fos")

    # save the synthesis to a json for comparison
    my_synthesis.save(r"synthesis/start_synthesis.json")

    # save the files to new files so that they don't overwrite the old ones.
    my_synthesis.save(r"synthesis/check01.fos")
    my_templates.save(r"templates/check01.fos")


    # some shortcuts so I don't need to keep referencing my_synthesis
    my_meta = my_synthesis.metadata
    my_exps = my_synthesis.experimenters
    my_reaction = my_synthesis.reaction
    my_mats = my_synthesis.cifs
    my_mats = my_synthesis.materials
    my_treats = my_synthesis.treatments


    my_synthesis.clear_all_comments()
    my_synthesis.rename_block("materials","reagents")
    my_mats = my_synthesis.reagents
    my_synthesis.rename.add_comments(
        "This new block has been added because I renamed a required block.")
    my_synthesis.rename.materials.add_comments(
        "Synthesis files are required to have a materials block, so",
        "this line specifies that it has been renamed to reagents.")

    my_exps[0].rename_block("affiliation","isu_research_group")
    my_synthesis.keys_to_end("cifs")
    my_synthesis.save("synthesis/check02.fos")


    # change some metadata for my synthesis
    my_meta.fos_id = "TE002"
    my_meta.description = "My Second Synthesis"
    my_meta.project_id = "travis5672/clathrates/As28+d"
    my_reaction.nominal_formula = "Ba8Cu13Zn11As28.5"

    my_synthesis.products = [{
        "name": "Barium transition-metal arsenide (8-24-28.5)",
        "formula": "Ba8Cu13Zn11As28.5",
        "expected": True,
        "obtained": True,
        "expected_amount": "250.0",
        "expected_amount_unit": "mg",
        "obtained_amount": "150.0",
        "obtained_amount_unit": "mg",
        "observations": "Gray Powder",
        "characterizations": "PXRD",
        "structure_comments": "Unique clathrate with variable occupancy on hyper-coordinate Arsenic site. Space group Cmcm"
    }]

    my_synthesis.save("synthesis/check03.fos")


    my_synthesis.clear_all_comments()
    # more shortcuts
    exp_temps = my_templates.experimenters
    mat_temps = my_templates.materials
    cif_temps = my_templates.cifs

    # template file has a template for Joe, but it's missing an affiliation value.
    # So I fill in the affiliation and add it to the experimenters on my synthesis
    joe_template = exp_temps.get_first(template_name="Joe")
    joe = joe_template.fill(affiliation="Kovnir Group - Iowa State University")
    my_exps.append(joe)
    my_exps.add_comments("Note that now there are two experimenters, so the",
                         "experimenters header has changed to double brackets")
    my_synthesis.save("synthesis/check04.fos")


    my_synthesis.clear_all_comments()

    travis = my_synthesis.experimenters[0]
    travis.add_block("friend","experimenter",joe.copy())
    travis.friend.affiliation = "Graham's Dad"

    travis.rename_block("friend","colleague")

    travis.colleague.add_comments("This copy of Joe has information about him as Travis's colleague")
    joe.name.add_comments("This copy of Joe has information about him as an experimenter")
    my_exps.add_comments("Note that there are now multiple experimenters in this block,",
                         "So the header now has double brackets")

    my_synthesis.save("synthesis/check05.fos")


    # Changing Barium's molar ratio
    my_mats[0].amount = 8


    # I find zinc in my materials, change its ratio, and also generate a template
    # from it.
    zinc = my_mats.get_first(form="powder")
    zinc.amount = 11

    # The template name is "A generic metal powder, purity 0.995", and it has empty
    # fields for name, formula, cas, and ratio
    powder_template = zinc.make_template("A generic metal powder, purity 0.995",
                                          "name","formula","cas","amount")
    powder_template.default_key_order()

    # This saves my powder template to a new category of templates titled "Generic$materials"
    my_templates.add_block("generic","materials", powder_template)
    my_templates.keys_to_end("cifs")


    # Setting up information that I want to fill into the powder template
    copper_info = {
        "name": "Copper",
        "formula": "Cu",
        "cas": "7440-50-8",
        "amount": 13
    }

    # Generate a new material, copper, from the template I made earlier and add it
    # to my synthesis materials
    copper = powder_template.fill(**copper_info)
    copper.clear_comments()
    my_mats.append(copper)

    # Here I'm using the arsenic template that was already in the template file to
    # replace antimony.
    arsenic_template = mat_temps.get_first(formula=ChemFormula("As"))
    arsenic = arsenic_template.fill(type="reagent", amount=28.5)
    my_mats.remove_any(cas="7440-36-0") # This removes the antimony from my synthesis
    my_mats.append(arsenic)

    clear = [file.clear_all_comments() for file in (my_synthesis, my_templates)]
    my_synthesis.save("synthesis/check06.fos")
    my_templates.save("templates/check06.fos")


    # Building templates from the existing annealing program on my synthesis so that
    # I can replace it with a different program.
    anneal_template = my_treats[2].make_template("Empty Anneal Template",
                                                 "repeats", "observations","program")
    anneal_template.clear_comments()
    ramp_template = my_treats[2].program[0].make_template("Any ramp",
                                                          "temp", "time")
    dwell_template = my_treats[2].program[1].make_template("Any dwell",
                                                           "time")
    # Save my new templates to my template file.
    my_templates.treatments = [anneal_template]
    my_templates.anneal_sections = [ramp_template, dwell_template]
    my_templates.keys_to_end("cifs")

    # Filling in my annealing templates
    ramp1 = ramp_template.fill(temp="550", time="2")
    ramp2 = ramp_template.fill(temp="650", time = "10")
    dwell1 = dwell_template.fill(time="12")
    dwell2 = dwell_template.fill(time="72")

    # Using my anneal template to create two different annealing treatments with my
    # different program sections.
    anneal1 = anneal_template.fill(repeats=1,
                                   observations="None",
                                   program=[ramp1, dwell1])
    anneal2 = anneal_template.fill(repeats=1,
                                   observations="None",
                                   program=[ramp2, dwell2])

    anneal1.program.append({"type":"quench","medium":"water"})

    my_templates.save("templates/check07.fos")


    # Remove all treatments except the first two
    my_treats.remove_idx(from_idx=2)

    # Adding both annealing treatments to my synthesis
    for anneal in (anneal1, anneal2):
        my_treats.append(anneal)

    my_synthesis.save("synthesis/check08.fos")


    # Copying Phil's cif from my templates into my synthesis.
    py618 = cif_temps[0].copy()
    my_synthesis.cifs.append(py618)

    # copying the Ba2Zn5Sb6 cif from my synthesis to my templates
    Ba2Zn5Sb6 = my_synthesis.cifs[0]
    cif_temps.insert(0,Ba2Zn5Sb6)

    # removing the Ba2Zn5Sb6 from my synthesis because it's not applicable for this
    # sample.
    my_synthesis.cifs.remove_any(file_name="Ba2Zn5Sb6_ICSD")

    my_templates.save("templates/check09.fos")
    my_synthesis.save("synthesis/check09.fos")


    # Every material gets a weight percent comment added above their ratio
    my_synthesis.add_calc_routine("reagents.add_weight_pcts")
    my_synthesis.reagents[0].amount.add_comments("Weight percents were calculated automatically when saving.")

    # Every anneal treatment gets missing rate parameter comment.
    for anneal in my_synthesis.treatments.get_any(type="anneal"):
        anneal.add_calc_routine("program.add_all_missing_parameters")



    # Reconfigure my_synthesis to copy attachments if location is changed,
    # instead of updating path to the original location.
    my_synthesis.track_attachments(new_copy=True, overwrite=True)
    # Path used to be "..\templates" (which resolves to example\templates)
    # New path is "." (which resolves to example\synthesis)
    # With new config, a new CIF will be copied to the new location when saving
    my_synthesis.cifs[0].path = "."


    # some reordering stuff to make the final printout more consistent.
    my_templates.default_key_order()
    my_templates.key_to_idx("generic", 3)
    my_templates.key_to_idx("anneal_sections", 5)
    my_templates.generic.set_list_type("explicit")

    my_synthesis.default_key_order()
    my_synthesis.key_to_idx("reagents", 5)
    my_mats.set_list_type("looped")

    my_templates.save("templates/check10.fos")
    my_synthesis.save("synthesis/check10.fos")

    # Silence all debugs except the one used for checking equality.
    all_debugs_off(soundoff=False)
    db._debug.on = True

    # Check to see if the saved file matches the current python object.
    print(f"Synthesis matches: {my_synthesis.matches_file()}")
    print(f"Templates match:   {my_templates.matches_file()}")


    # optional: figure
    # my_synthesis.cifs[0].quick_pattern(subprocess=True)


    # optional: figure
    # my_synthesis.treatments.get_first(type="anneal").show_plot()

if __name__ == '__main__':
    main()