def test_vmec(self):
        """
        If we run VMEC using a given boundary shape, then convert the
        boundary to the Henneberg representation and convert back and
        run VMEC again, the rotational transform should be almost
        identical.
        """
        vmec = Vmec(os.path.join(TEST_DIR, 'input.cfqs_2b40'))
        vmec.run()
        iota1 = vmec.wout.iotaf

        vmec.boundary = SurfaceHenneberg.from_RZFourier(vmec.boundary, 1)
        vmec.need_to_run_code = True
        vmec.run()
        iota2 = vmec.wout.iotaf

        logger.info(f'iota1: {iota1}')
        logger.info(f'iota2: {iota2}')
        logger.info(f'diff: {iota1 - iota2}')
        np.testing.assert_allclose(iota1, iota2, atol=1e-3, rtol=1e-3)
        # But if the 2 iota profiles are _exactly_ the same, vmec must
        # not have actually used the converted boundary.
        self.assertTrue(np.max(np.abs(iota1 - iota2)) > 1e-12)
    def test_from_RZFourier(self):
        """
        Take a VMEC boundary in the original RZFourier representation,
        convert it to the Henneberg representation, and convert it
        back to the RZFourier representation. Coordinate-independent
        quantities like the volume and area should not change. If the
        result is converted to the Henneberg representation yet again,
        the degrees of freedom should be unchanged from the earlier
        Henneberg representation.
        """
        # Prepare some arbitrary points for testing gamma_lin:
        nlist = 15
        theta_list = np.linspace(-0.2, 0.8, nlist)
        phi_list = theta_list**2 - 0.5

        # Try a QI, QA, and a QH:
        files = [
            'input.W7-X_standard_configuration', 'input.cfqs_2b40',
            'input.NuhrenbergZille_1988_QHS'
        ]
        alpha_facs = [1, 1, -1]

        for test_file, alpha_fac in zip(files, alpha_facs):
            vmec = Vmec(os.path.join(TEST_DIR, test_file))
            surf1 = vmec.boundary
            surf2 = SurfaceHenneberg.from_RZFourier(surf1, alpha_fac)
            self.assertEqual(surf2.num_dofs(), len(surf2.get_dofs()))
            surf3 = surf2.to_RZFourier()

            # Test gamma_lin:
            gamma2 = np.zeros((nlist, 3))
            gamma3 = np.zeros((nlist, 3))
            surf2.gamma_lin(gamma2, phi_list, theta_list)
            surf3.gamma_lin(gamma3, phi_list, theta_list)
            np.testing.assert_allclose(gamma2, gamma3, atol=1e-13, rtol=1e-13)

            # Test other surface functions:
            np.testing.assert_allclose(surf2.gamma(),
                                       surf3.gamma(),
                                       atol=1e-13,
                                       rtol=1e-13)
            np.testing.assert_allclose(surf2.gammadash2(),
                                       surf3.gammadash2(),
                                       atol=1e-12,
                                       rtol=1e-12)
            np.testing.assert_allclose(surf2.gammadash1(),
                                       surf3.gammadash1(),
                                       atol=1e-11,
                                       rtol=1e-11)
            np.testing.assert_allclose(surf1.volume(),
                                       surf2.volume(),
                                       atol=0,
                                       rtol=1e-3)
            np.testing.assert_allclose(surf1.volume(),
                                       surf3.volume(),
                                       atol=0,
                                       rtol=1e-3)
            np.testing.assert_allclose(surf1.area(),
                                       surf2.area(),
                                       atol=0,
                                       rtol=1e-3)
            np.testing.assert_allclose(surf1.area(),
                                       surf3.area(),
                                       atol=0,
                                       rtol=1e-3)
            surf4 = SurfaceHenneberg.from_RZFourier(surf3,
                                                    alpha_fac,
                                                    mmax=surf2.mmax,
                                                    nmax=surf2.nmax)
            np.testing.assert_allclose(surf2.R0nH,
                                       surf4.R0nH,
                                       atol=1e-12,
                                       rtol=1e-4)
            np.testing.assert_allclose(surf2.Z0nH,
                                       surf4.Z0nH,
                                       atol=1e-12,
                                       rtol=1e-4)
            np.testing.assert_allclose(surf2.bn,
                                       surf4.bn,
                                       atol=1e-12,
                                       rtol=1e-4)
            np.testing.assert_allclose(surf2.rhomn,
                                       surf4.rhomn,
                                       atol=1e-8,
                                       rtol=1e-4)