{ "cells": [ { "cell_type": "markdown", "id": "5b58d1cb", "metadata": {}, "source": [ "# Converting to OpenFTS2\n", "\n", "In March 2025, the OpenFTS python API was significantly updated in order to be more modular and more object oriented. This new interface (OpenFTS2), replaces the old interface (OpenFTS1) and requires user to update all input files. This page describes the details of this update and the updates that are required.\n", "\n", "**\n", "\n", "We first will import the `openfts` module as before" ] }, { "cell_type": "code", "execution_count": 1, "id": "a3122974", "metadata": {}, "outputs": [], "source": [ "import openfts" ] }, { "cell_type": "markdown", "id": "13220011", "metadata": {}, "source": [ "In order to compare OpenFTS1 and OpenFTS2, we will explicitly create an `OpenFTS1` object and an `OpenFTS2` object" ] }, { "cell_type": "code", "execution_count": 2, "id": "348da3fe", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "/home/jl4346/LequieuLab/OpenFTS-new-python-interface/build/python/openfts/openfts1.py:19: UserWarning: OpenFTS1 has been deprecated. Consider using OpenFTS2 instead\n", " warnings.warn(\"OpenFTS1 has been deprecated. Consider using OpenFTS2 instead\")\n" ] } ], "source": [ "fts1 = openfts.OpenFTS1()\n", "print(fts1)" ] }, { "cell_type": "code", "execution_count": 3, "id": "4601d9cf", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n" ] } ], "source": [ "fts2 = openfts.OpenFTS2()\n", "print(fts2)" ] }, { "cell_type": "markdown", "id": "b4fb8cfe", "metadata": {}, "source": [ "Note that The OpenFTS1 object throws a warning and will eventually be removed.\n", "\n", "By default the `OpenFTS()` constructor creates an `OpenFTS2` object" ] }, { "cell_type": "code", "execution_count": 4, "id": "b55cf764", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n" ] } ], "source": [ "fts = openfts.OpenFTS()\n", "print(fts)" ] }, { "cell_type": "markdown", "id": "8ca7018d", "metadata": {}, "source": [ "In `OpenFTS1`, the cell was specified using the `cell` **method** of the `OpenFTS1` object:" ] }, { "cell_type": "code", "execution_count": 5, "id": "ae63e393", "metadata": {}, "outputs": [], "source": [ "fts1.cell(cell_scale=1.0, cell_lengths=[4.3], dimension=1, length_unit='Rg')" ] }, { "cell_type": "markdown", "id": "20d72b82", "metadata": {}, "source": [ "In `OpenFTS1`, if the user wanted to modify any of these arguements after the `cell` **method** was called, the user needed to tweak the `fts1.params` dictionary:" ] }, { "cell_type": "code", "execution_count": 6, "id": "3aa93b9f", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Original: {'cell_scale': 1.0, 'cell_lengths': [4.3], 'dimension': 1, 'length_unit': 'Rg'}\n", "Updated: {'cell_scale': 5.0, 'cell_lengths': [4.3], 'dimension': 1, 'length_unit': 'Rg'}\n" ] } ], "source": [ "print(\"Original: \", fts1.params['cell'])\n", "fts1.params['cell']['cell_scale'] = 5.0\n", "print(\"Updated: \", fts1.params['cell'])" ] }, { "cell_type": "markdown", "id": "353c46ad", "metadata": {}, "source": [ "In `OpenFTS2`, this structure has been replaced, by instead having the user create and store a `Cell` **object**:" ] }, { "cell_type": "code", "execution_count": 7, "id": "53bcb2a2", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n" ] } ], "source": [ "fts2.cell = openfts.Cell(cell_scale=1.0, cell_lengths=[4.3], dimension=1, length_unit='Rg')\n", "print(fts2.cell)" ] }, { "cell_type": "markdown", "id": "28cc1af1", "metadata": {}, "source": [ "The elements of the `OpenFTS2` `cell` object are directly accessible as member variable and can be directly modified :" ] }, { "cell_type": "code", "execution_count": 8, "id": "8652d99a", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Original cell_scale: 1.0\n", "Updated cell_scale: 5.0\n" ] } ], "source": [ "print(\"Original cell_scale: \", fts2.cell.cell_scale)\n", "fts2.cell.cell_scale = 5.0\n", "print(\"Updated cell_scale: \", fts2.cell.cell_scale)" ] }, { "cell_type": "markdown", "id": "1e412c35", "metadata": {}, "source": [ "For convenience, in `OpenFTS2`, the elements of this `cell` object can be printed using the `to_dict()` member method:" ] }, { "cell_type": "code", "execution_count": 9, "id": "ff5db5d9", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'cell_scale': 5.0, 'cell_lengths': [4.3], 'dimension': 1, 'length_unit': 'Rg'}" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "fts2.cell.to_dict()" ] }, { "cell_type": "markdown", "id": "5e4613c7", "metadata": {}, "source": [ "For users who have previously developed workflows using OpenFTS1, these workflows can be converted to OpenFTS2 be replacing the nested dictionary structure previously found in `fts1.params` with the use of dot operators. As an example, to access the exchange fields filename from output you would use" ] }, { "cell_type": "code", "execution_count": 10, "id": "93407757", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "filename (fts1) = fields.dat\n", "filename (fts2) = fields.dat\n" ] } ], "source": [ "fts1.output_default()\n", "filename1 = fts1.params[\"output\"][\"fields\"][\"exchange_fields\"][\"file\"]\n", "print(\"filename (fts1) = \", filename1)\n", "\n", "fts2.output = openfts.Output() \n", "filename2 = fts2.output.fields.exchange_fields.file\n", "print(\"filename (fts2) = \", filename2)" ] }, { "cell_type": "markdown", "id": "7332c420", "metadata": {}, "source": [ " For convenience, a tool to convert from `OpenFTS1` to `OpenFTS2` is provided in `OpenFTS/python/tools/convert_to_openfts2.py`. \n", "\n", "This tool changes all of the function calls (fts.cell, fts.driver, etc.) to use the new objects. \n", "\n", "**WARNING**: The conversion tool only works with simple files. If the code changes fts.params, for example, that will have to be changed manually to use OpenFTS2." ] }, { "cell_type": "markdown", "id": "00e409ea", "metadata": {}, "source": [ "For comparison, the input files for simple diblock simulation in OpenFTS1 and OpenFTS2 are shown below\n", "\n", "## OpenFTS2 (the default)" ] }, { "cell_type": "code", "execution_count": 11, "id": "f842226f", "metadata": {}, "outputs": [], "source": [ "fts = openfts.OpenFTS() \n", "\n", "# initialize the cell\n", "fts.cell = openfts.Cell(cell_scale=1.0,cell_lengths=[4.3],dimension=1,length_unit='Rg')\n", "\n", "# initialize the fields to use 32 grid points\n", "fts.field_layout = openfts.FieldLayout(npw=[32],random_seed=1)\n", "\n", "# initialize the driver (including the field updater and variable cell)\n", "scft = openfts.driver.SCFT(dt=5.0,nsteps=4000,output_freq=50,stop_tolerance=1e-05,)\n", "scft.field_updater = openfts.field_updater.EMPEC(update_order='simultaneous',adaptive_timestep=False,lambdas=[1.0, 1.0])\n", "scft.variable_cell = openfts.VariableCell(lambda_=0.2,stop_tolerance=0.0001,update_freq=20,shape_constraint='none')\n", "fts.driver = scft\n", "\n", "# number of beads in chain\n", "N = 50\n", "\n", "# Create the model with chiN=20 and BC=100\n", "chiAB = openfts.model.ChiAB( Nref=N,bref=1.0,chiN=20.,inverse_BC=0.01)\n", "\n", "# initialize the model fields\n", "# mu_minus is initialized with a gaussian centered at zero, mu_plus is random\n", "chiAB.init_fields['mu_minus'] = openfts.init_field.Gaussian(height=1.0,ngaussian=1,width=0.1,centers=[0])\n", "chiAB.init_fields['mu_plus'] = openfts.init_field.Random(mean=0.0,stdev=1.0)\n", "fts.model = chiAB\n", "\n", "# create a molecule, here a diblock consisting of N beads with fA=0.5\n", "diblock = openfts.molecule.PolymerLinearDiscrete(nbeads=N,nblocks=2,block_fractions=[0.5, 0.5],\n", " block_species=['A', 'B'],volume_frac=1.0)\n", "fts.molecules.append(diblock)\n", "\n", "# Set the operators we seek to output\n", "# for SCFT the Hamiltonian and CellStress are sufficient\n", "fts.operators.append(openfts.operator.Hamiltonian(averaging_type='none'))\n", "fts.operators.append(openfts.operator.CellStress(averaging_type='none'))\n", "\n", "# Use the default names of output files\n", "fts.output = openfts.Output()\n", "\n", "# Use two species types A and B, each with a smearing length of 0.15 Rg\n", "fts.species.append(openfts.Species(label='A',stat_segment_length=1.0, smearing_length=0.15))\n", "fts.species.append(openfts.Species(label='B',stat_segment_length=1.0, smearing_length=0.15))\n", "\n", "#fts.run()" ] }, { "cell_type": "markdown", "id": "9b4ede7b-647f-4b0f-8107-c20157c65bfa", "metadata": {}, "source": [ "## OpenFTS1 (depreciated)" ] }, { "cell_type": "code", "execution_count": 12, "id": "9e72a24c", "metadata": {}, "outputs": [], "source": [ "# create an OpenFTS object\n", "fts = openfts.OpenFTS1()\n", "\n", "# initialize the cell\n", "fts.cell(cell_scale=1.0,cell_lengths=[4.3],dimension=1,length_unit='Rg')\n", "\n", "# initialize the fields to use 32 grid points\n", "fts.field_layout(npw=[32],random_seed=1)\n", "\n", "# initialize the driver (including the field updater and variable cell)\n", "fts.driver(dt=5.0,nsteps=4000,output_freq=50,type='SCFT',stop_tolerance=1e-05,)\n", "fts.field_updater(type='EMPEC',update_order='simultaneous',adaptive_timestep=False,lambdas=[1.0, 1.0])\n", "fts.variable_cell(lambda_=0.2,stop_tolerance=0.0001,update_freq=20,shape_constraint='none')\n", "\n", "# number of beads in chain\n", "N = 50\n", "\n", "# Create the model with chiN=20 and BC=100\n", "fts.model(type='MeltChiAB', Nref=N,bref=1.0,chiN=20.,inverse_BC=0.01)\n", "\n", "# initialize the model fields\n", "# mu_minus is initialized with a gaussian centered at zero, mu_plus is random\n", "fts.init_model_field(fieldname='mu_minus',type='gaussians', height=1.0,ngaussian=1,width=0.1,centers=[0])\n", "fts.init_model_field(fieldname='mu_plus',type='random',mean=0.0,stdev=1.0)\n", "\n", "# create a molecule, here a diblock consisting of N beads with fA=0.5\n", "fts.add_molecule(type='PolymerLinear',chain_type='discrete',\n", " nbeads=N,nblocks=2,block_fractions=[0.5, 0.5],block_species=['A', 'B'],\n", " volume_frac=1.0)\n", "\n", "# Set the operators we seek to output\n", "# for SCFT the Hamiltonian and CellStress are sufficient\n", "fts.add_operator(averaging_type='none',type='Hamiltonian')\n", "fts.add_operator(averaging_type='none',type='CellStress')\n", "\n", "# Use the default names of output files\n", "fts.output_default()\n", "\n", "# Use two species types A and B, each with a smearing length of 0.15 Rg\n", "fts.add_species(label='A',stat_segment_length=1.0, smearing_length=0.15)\n", "fts.add_species(label='B',stat_segment_length=1.0, smearing_length=0.15)\n", "\n", "#fts.run()" ] } ], "metadata": { "kernelspec": { "display_name": "Python (base env)", "language": "python", "name": "base" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.11.4" } }, "nbformat": 4, "nbformat_minor": 5 }