text:
# Chemfiles.jl, a modern library for chemistry file reading and writing
# Copyright (C) Guillaume Fraux and contributors -- BSD license
#
# =========================================================================== #
# !!!! AUTO-GENERATED FILE !!!! Do not edit. See the bindgen repository for
# the generation code (https://github.com/chemfiles/bindgen).
# This file contains Julia interface to the C API
# =========================================================================== #

# Function 'chfl_version' at types.h:145
function chfl_version()
    ccall((:chfl_version, libchemfiles), Ptr{UInt8}, (), )
end

# Function 'chfl_last_error' at misc.h:19
function chfl_last_error()
    ccall((:chfl_last_error, libchemfiles), Ptr{UInt8}, (), )
end

# Function 'chfl_clear_errors' at misc.h:29
function chfl_clear_errors()
    ccall((:chfl_clear_errors, libchemfiles), chfl_status, (), )
end

# Function 'chfl_set_warning_callback' at misc.h:38
function chfl_set_warning_callback(callback::Ptr{Void})
    ccall((:chfl_set_warning_callback, libchemfiles), chfl_status, (Ptr{Void},), callback)
end

# Function 'chfl_add_configuration' at misc.h:53
function chfl_add_configuration(path::Ptr{UInt8})
    ccall((:chfl_add_configuration, libchemfiles), chfl_status, (Ptr{UInt8},), path)
end

# Function 'chfl_property_bool' at property.h:32
function chfl_property_bool(value::Cbool)
    ccall((:chfl_property_bool, libchemfiles), Ptr{CHFL_PROPERTY}, (Cbool,), value)
end

# Function 'chfl_property_double' at property.h:42
function chfl_property_double(value::Cdouble)
    ccall((:chfl_property_double, libchemfiles), Ptr{CHFL_PROPERTY}, (Cdouble,), value)
end

# Function 'chfl_property_string' at property.h:52
function chfl_property_string(value::Ptr{UInt8})
    ccall((:chfl_property_string, libchemfiles), Ptr{CHFL_PROPERTY}, (Ptr{UInt8},), value)
end

# Function 'chfl_property_vector3d' at property.h:62
function chfl_property_vector3d(value::chfl_vector3d)
    ccall((:chfl_property_vector3d, libchemfiles), Ptr{CHFL_PROPERTY}, (Ptr{Float64},), value)
end

# Function 'chfl_property_get_kind' at property.h:69
function chfl_property_get_kind(property::Ptr{CHFL_PROPERTY}, kind::Ref{chfl_property_kind})
    ccall((:chfl_property_get_kind, libchemfiles), chfl_status, (Ptr{CHFL_PROPERTY}, Ref{chfl_property_kind}), property, kind)
end

# Function 'chfl_property_get_bool' at property.h:82
function chfl_property_get_bool(property::Ptr{CHFL_PROPERTY}, value::Ref{Cbool})
    ccall((:chfl_property_get_bool, libchemfiles), chfl_status, (Ptr{CHFL_PROPERTY}, Ref{Cbool}), property, value)
end

# Function 'chfl_property_get_double' at property.h:95
function chfl_property_get_double(property::Ptr{CHFL_PROPERTY}, value::Ref{Cdouble})
    ccall((:chfl_property_get_double, libchemfiles), chfl_status, (Ptr{CHFL_PROPERTY}, Ref{Cdouble}), property, value)
end

# Function 'chfl_property_get_string' at property.h:110
function chfl_property_get_string(property::Ptr{CHFL_PROPERTY}, buffer::Ptr{UInt8}, buffsize::UInt64)
    ccall((:chfl_property_get_string, libchemfiles), chfl_status, (Ptr{CHFL_PROPERTY}, Ptr{UInt8}, UInt64), property, buffer, buffsize)
end

# Function 'chfl_property_get_vector3d' at property.h:123
function chfl_property_get_vector3d(property::Ptr{CHFL_PROPERTY}, value::chfl_vector3d)
    ccall((:chfl_property_get_vector3d, libchemfiles), chfl_status, (Ptr{CHFL_PROPERTY}, Ptr{Float64}), property, value)
end

# Function 'chfl_property_free' at property.h:131
function chfl_property_free(property::Ptr{CHFL_PROPERTY})
    ccall((:chfl_property_free, libchemfiles), chfl_status, (Ptr{CHFL_PROPERTY},), property)
end

# Function 'chfl_atom' at atom.h:20
function chfl_atom(name::Ptr{UInt8})
    ccall((:chfl_atom, libchemfiles), Ptr{CHFL_ATOM}, (Ptr{UInt8},), name)
end

# Function 'chfl_atom_copy' at atom.h:30
function chfl_atom_copy(atom::Ptr{CHFL_ATOM})
    ccall((:chfl_atom_copy, libchemfiles), Ptr{CHFL_ATOM}, (Ptr{CHFL_ATOM},), atom)
end

# Function 'chfl_atom_from_frame' at atom.h:42
function chfl_atom_from_frame(frame::Ptr{CHFL_FRAME}, index::UInt64)
    ccall((:chfl_atom_from_frame, libchemfiles), Ptr{CHFL_ATOM}, (Ptr{CHFL_FRAME}, UInt64), frame, index)
end

# Function 'chfl_atom_from_topology' at atom.h:53
function chfl_atom_from_topology(topology::Ptr{CHFL_TOPOLOGY}, index::UInt64)
    ccall((:chfl_atom_from_topology, libchemfiles), Ptr{CHFL_ATOM}, (Ptr{CHFL_TOPOLOGY}, UInt64), topology, index)
end

# Function 'chfl_atom_mass' at atom.h:64
function chfl_atom_mass(atom::Ptr{CHFL_ATOM}, mass::Ref{Cdouble})
    ccall((:chfl_atom_mass, libchemfiles), chfl_status, (Ptr{CHFL_ATOM}, Ref{Cdouble}), atom, mass)
end

# Function 'chfl_atom_set_mass' at atom.h:73
function chfl_atom_set_mass(atom::Ptr{CHFL_ATOM}, mass::Cdouble)
    ccall((:chfl_atom_set_mass, libchemfiles), chfl_status, (Ptr{CHFL_ATOM}, Cdouble), atom, mass)
end

# Function 'chfl_atom_charge' at atom.h:82
function chfl_atom_charge(atom::Ptr{CHFL_ATOM}, charge::Ref{Cdouble})
    ccall((:chfl_atom_charge, libchemfiles), chfl_status, (Ptr{CHFL_ATOM}, Ref{Cdouble}), atom, charge)
end

# Function 'chfl_atom_set_charge' at atom.h:91
function chfl_atom_set_charge(atom::Ptr{CHFL_ATOM}, charge::Cdouble)
    ccall((:chfl_atom_set_charge, libchemfiles), chfl_status, (Ptr{CHFL_ATOM}, Cdouble), atom, charge)
end

# Function 'chfl_atom_type' at atom.h:101
function chfl_atom_type(atom::Ptr{CHFL_ATOM}, typ::Ptr{UInt8}, buffsize::UInt64)
    ccall((:chfl_atom_type, libchemfiles), chfl_status, (Ptr{CHFL_ATOM}, Ptr{UInt8}, UInt64), atom, typ, buffsize)
end

# Function 'chfl_atom_set_type' at atom.h:112
function chfl_atom_set_type(atom::Ptr{CHFL_ATOM}, typ::Ptr{UInt8})
    ccall((:chfl_atom_set_type, libchemfiles), chfl_status, (Ptr{CHFL_ATOM}, Ptr{UInt8}), atom, typ)
end

# Function 'chfl_atom_name' at atom.h:122
function chfl_atom_name(atom::Ptr{CHFL_ATOM}, name::Ptr{UInt8}, buffsize::UInt64)
    ccall((:chfl_atom_name, libchemfiles), chfl_status, (Ptr{CHFL_ATOM}, Ptr{UInt8}, UInt64), atom, name, buffsize)
end

# Function 'chfl_atom_set_name' at atom.h:133
function chfl_atom_set_name(atom::Ptr{CHFL_ATOM}, name::Ptr{UInt8})
    ccall((:chfl_atom_set_name, libchemfiles), chfl_status, (Ptr{CHFL_ATOM}, Ptr{UInt8}), atom, name)
end

# Function 'chfl_atom_full_name' at atom.h:143
function chfl_atom_full_name(atom::Ptr{CHFL_ATOM}, name::Ptr{UInt8}, buffsize::UInt64)
    ccall((:chfl_atom_full_name, libchemfiles), chfl_status, (Ptr{CHFL_ATOM}, Ptr{UInt8}, UInt64), atom, name, buffsize)
end

# Function 'chfl_atom_vdw_radius' at atom.h:155
function chfl_atom_vdw_radius(atom::Ptr{CHFL_ATOM}, radius::Ref{Cdouble})
    ccall((:chfl_atom_vdw_radius, libchemfiles), chfl_status, (Ptr{CHFL_ATOM}, Ref{Cdouble}), atom, radius)
end

# Function 'chfl_atom_covalent_radius' at atom.h:165
function chfl_atom_covalent_radius(atom::Ptr{CHFL_ATOM}, radius::Ref{Cdouble})
    ccall((:chfl_atom_covalent_radius, libchemfiles), chfl_status, (Ptr{CHFL_ATOM}, Ref{Cdouble}), atom, radius)
end

# Function 'chfl_atom_atomic_number' at atom.h:175
function chfl_atom_atomic_number(atom::Ptr{CHFL_ATOM}, number::Ref{UInt64})
    ccall((:chfl_atom_atomic_number, libchemfiles), chfl_status, (Ptr{CHFL_ATOM}, Ref{UInt64}), atom, number)
end

# Function 'chfl_atom_set_property' at atom.h:185
function chfl_atom_set_property(atom::Ptr{CHFL_ATOM}, name::Ptr{UInt8}, property::Ptr{CHFL_PROPERTY})
    ccall((:chfl_atom_set_property, libchemfiles), chfl_status, (Ptr{CHFL_ATOM}, Ptr{UInt8}, Ptr{CHFL_PROPERTY}), atom, name, property)
end

# Function 'chfl_atom_get_property' at atom.h:199
function chfl_atom_get_property(atom::Ptr{CHFL_ATOM}, name::Ptr{UInt8})
    ccall((:chfl_atom_get_property, libchemfiles), Ptr{CHFL_PROPERTY}, (Ptr{CHFL_ATOM}, Ptr{UInt8}), atom, name)
end

# Function 'chfl_atom_free' at atom.h:207
function chfl_atom_free(atom::Ptr{CHFL_ATOM})
    ccall((:chfl_atom_free, libchemfiles), chfl_status, (Ptr{CHFL_ATOM},), atom)
end

# Function 'chfl_residue' at residue.h:20
function chfl_residue(name::Ptr{UInt8})
    ccall((:chfl_residue, libchemfiles), Ptr{CHFL_RESIDUE}, (Ptr{UInt8},), name)
end

# Function 'chfl_residue_with_id' at residue.h:30
function chfl_residue_with_id(name::Ptr{UInt8}, resid::UInt64)
    ccall((:chfl_residue_with_id, libchemfiles), Ptr{CHFL_RESIDUE}, (Ptr{UInt8}, UInt64), name, resid)
end

# Function 'chfl_residue_from_topology' at residue.h:46
function chfl_residue_from_topology(topology::Ptr{CHFL_TOPOLOGY}, i::UInt64)
    ccall((:chfl_residue_from_topology, libchemfiles), Ptr{CHFL_RESIDUE}, (Ptr{CHFL_TOPOLOGY}, UInt64), topology, i)
end

# Function 'chfl_residue_for_atom' at residue.h:62
function chfl_residue_for_atom(topology::Ptr{CHFL_TOPOLOGY}, i::UInt64)
    ccall((:chfl_residue_for_atom, libchemfiles), Ptr{CHFL_RESIDUE}, (Ptr{CHFL_TOPOLOGY}, UInt64), topology, i)
end

# Function 'chfl_residue_copy' at residue.h:74
function chfl_residue_copy(residue::Ptr{CHFL_RESIDUE})
    ccall((:chfl_residue_copy, libchemfiles), Ptr{CHFL_RESIDUE}, (Ptr{CHFL_RESIDUE},), residue)
end

# Function 'chfl_residue_atoms_count' at residue.h:81
function chfl_residue_atoms_count(residue::Ptr{CHFL_RESIDUE}, size::Ref{UInt64})
    ccall((:chfl_residue_atoms_count, libchemfiles), chfl_status, (Ptr{CHFL_RESIDUE}, Ref{UInt64}), residue, size)
end

# Function 'chfl_residue_atoms' at residue.h:95
function chfl_residue_atoms(residue::Ptr{CHFL_RESIDUE}, atoms::Ptr{UInt64}, natoms::UInt64)
    ccall((:chfl_residue_atoms, libchemfiles), chfl_status, (Ptr{CHFL_RESIDUE}, Ptr{UInt64}, UInt64), residue, atoms, natoms)
end

# Function 'chfl_residue_id' at residue.h:108
function chfl_residue_id(residue::Ptr{CHFL_RESIDUE}, id::Ref{UInt64})
    ccall((:chfl_residue_id, libchemfiles), chfl_status, (Ptr{CHFL_RESIDUE}, Ref{UInt64}), residue, id)
end

# Function 'chfl_residue_name' at residue.h:120
function chfl_residue_name(residue::Ptr{CHFL_RESIDUE}, name::Ptr{UInt8}, buffsize::UInt64)
    ccall((:chfl_residue_name, libchemfiles), chfl_status, (Ptr{CHFL_RESIDUE}, Ptr{UInt8}, UInt64), residue, name, buffsize)
end

# Function 'chfl_residue_add_atom' at residue.h:129
function chfl_residue_add_atom(residue::Ptr{CHFL_RESIDUE}, i::UInt64)
    ccall((:chfl_residue_add_atom, libchemfiles), chfl_status, (Ptr{CHFL_RESIDUE}, UInt64), residue, i)
end

# Function 'chfl_residue_contains' at residue.h:139
function chfl_residue_contains(residue::Ptr{CHFL_RESIDUE}, i::UInt64, result::Ref{Cbool})
    ccall((:chfl_residue_contains, libchemfiles), chfl_status, (Ptr{CHFL_RESIDUE}, UInt64, Ref{Cbool}), residue, i, result)
end

# Function 'chfl_residue_free' at residue.h:147
function chfl_residue_free(residue::Ptr{CHFL_RESIDUE})
    ccall((:chfl_residue_free, libchemfiles), chfl_status, (Ptr{CHFL_RESIDUE},), residue)
end

# Function 'chfl_topology' at topology.h:20
function chfl_topology()
    ccall((:chfl_topology, libchemfiles), Ptr{CHFL_TOPOLOGY}, (), )
end

# Function 'chfl_topology_from_frame' at topology.h:30
function chfl_topology_from_frame(frame::Ptr{CHFL_FRAME})
    ccall((:chfl_topology_from_frame, libchemfiles), Ptr{CHFL_TOPOLOGY}, (Ptr{CHFL_FRAME},), frame)
end

# Function 'chfl_topology_copy' at topology.h:40
function chfl_topology_copy(topology::Ptr{CHFL_TOPOLOGY})
    ccall((:chfl_topology_copy, libchemfiles), Ptr{CHFL_TOPOLOGY}, (Ptr{CHFL_TOPOLOGY},), topology)
end

# Function 'chfl_topology_atoms_count' at topology.h:48
function chfl_topology_atoms_count(topology::Ptr{CHFL_TOPOLOGY}, size::Ref{UInt64})
    ccall((:chfl_topology_atoms_count, libchemfiles), chfl_status, (Ptr{CHFL_TOPOLOGY}, Ref{UInt64}), topology, size)
end

# Function 'chfl_topology_resize' at topology.h:60
function chfl_topology_resize(topology::Ptr{CHFL_TOPOLOGY}, natoms::UInt64)
    ccall((:chfl_topology_resize, libchemfiles), chfl_status, (Ptr{CHFL_TOPOLOGY}, UInt64), topology, natoms)
end

# Function 'chfl_topology_add_atom' at topology.h:67
function chfl_topology_add_atom(topology::Ptr{CHFL_TOPOLOGY}, atom::Ptr{CHFL_ATOM})
    ccall((:chfl_topology_add_atom, libchemfiles), chfl_status, (Ptr{CHFL_TOPOLOGY}, Ptr{CHFL_ATOM}), topology, atom)
end

# Function 'chfl_topology_remove' at topology.h:78
function chfl_topology_remove(topology::Ptr{CHFL_TOPOLOGY}, i::UInt64)
    ccall((:chfl_topology_remove, libchemfiles), chfl_status, (Ptr{CHFL_TOPOLOGY}, UInt64), topology, i)
end

# Function 'chfl_topology_bonds_count' at topology.h:87
function chfl_topology_bonds_count(topology::Ptr{CHFL_TOPOLOGY}, nbonds::Ref{UInt64})
    ccall((:chfl_topology_bonds_count, libchemfiles), chfl_status, (Ptr{CHFL_TOPOLOGY}, Ref{UInt64}), topology, nbonds)
end

# Function 'chfl_topology_angles_count' at topology.h:96
function chfl_topology_angles_count(topology::Ptr{CHFL_TOPOLOGY}, nangles::Ref{UInt64})
    ccall((:chfl_topology_angles_count, libchemfiles), chfl_status, (Ptr{CHFL_TOPOLOGY}, Ref{UInt64}), topology, nangles)
end

# Function 'chfl_topology_dihedrals_count' at topology.h:105
function chfl_topology_dihedrals_count(topology::Ptr{CHFL_TOPOLOGY}, ndihedrals::Ref{UInt64})
    ccall((:chfl_topology_dihedrals_count, libchemfiles), chfl_status, (Ptr{CHFL_TOPOLOGY}, Ref{UInt64}), topology, ndihedrals)
end

# Function 'chfl_topology_impropers_count' at topology.h:114
function chfl_topology_impropers_count(topology::Ptr{CHFL_TOPOLOGY}, nimpropers::Ref{UInt64})
    ccall((:chfl_topology_impropers_count, libchemfiles), chfl_status, (Ptr{CHFL_TOPOLOGY}, Ref{UInt64}), topology, nimpropers)
end

# Function 'chfl_topology_bonds' at topology.h:127
function chfl_topology_bonds(topology::Ptr{CHFL_TOPOLOGY}, data::Ptr{UInt64}, nbonds::UInt64)
    ccall((:chfl_topology_bonds, libchemfiles), chfl_status, (Ptr{CHFL_TOPOLOGY}, Ptr{UInt64}, UInt64), topology, data, nbonds)
end

# Function 'chfl_topology_angles' at topology.h:140
function chfl_topology_angles(topology::Ptr{CHFL_TOPOLOGY}, data::Ptr{UInt64}, nangles::UInt64)
    ccall((:chfl_topology_angles, libchemfiles), chfl_status, (Ptr{CHFL_TOPOLOGY}, Ptr{UInt64}, UInt64), topology, data, nangles)
end

# Function 'chfl_topology_dihedrals' at topology.h:154
function chfl_topology_dihedrals(topology::Ptr{CHFL_TOPOLOGY}, data::Ptr{UInt64}, ndihedrals::UInt64)
    ccall((:chfl_topology_dihedrals, libchemfiles), chfl_status, (Ptr{CHFL_TOPOLOGY}, Ptr{UInt64}, UInt64), topology, data, ndihedrals)
end

# Function 'chfl_topology_impropers' at topology.h:168
function chfl_topology_impropers(topology::Ptr{CHFL_TOPOLOGY}, data::Ptr{UInt64}, nimpropers::UInt64)
    ccall((:chfl_topology_impropers, libchemfiles), chfl_status, (Ptr{CHFL_TOPOLOGY}, Ptr{UInt64}, UInt64), topology, data, nimpropers)
end

# Function 'chfl_topology_add_bond' at topology.h:177
function chfl_topology_add_bond(topology::Ptr{CHFL_TOPOLOGY}, i::UInt64, j::UInt64)
    ccall((:chfl_topology_add_bond, libchemfiles), chfl_status, (Ptr{CHFL_TOPOLOGY}, UInt64, UInt64), topology, i, j)
end

# Function 'chfl_topology_remove_bond' at topology.h:189
function chfl_topology_remove_bond(topology::Ptr{CHFL_TOPOLOGY}, i::UInt64, j::UInt64)
    ccall((:chfl_topology_remove_bond, libchemfiles), chfl_status, (Ptr{CHFL_TOPOLOGY}, UInt64, UInt64), topology, i, j)
end

# Function 'chfl_topology_residues_count' at topology.h:199
function chfl_topology_residues_count(topology::Ptr{CHFL_TOPOLOGY}, residues::Ref{UInt64})
    ccall((:chfl_topology_residues_count, libchemfiles), chfl_status, (Ptr{CHFL_TOPOLOGY}, Ref{UInt64}), topology, residues)
end

# Function 'chfl_topology_add_residue' at topology.h:211
function chfl_topology_add_residue(topology::Ptr{CHFL_TOPOLOGY}, residue::Ptr{CHFL_RESIDUE})
    ccall((:chfl_topology_add_residue, libchemfiles), chfl_status, (Ptr{CHFL_TOPOLOGY}, Ptr{CHFL_RESIDUE}), topology, residue)
end

# Function 'chfl_topology_residues_linked' at topology.h:222
function chfl_topology_residues_linked(topology::Ptr{CHFL_TOPOLOGY}, first::Ptr{CHFL_RESIDUE}, second::Ptr{CHFL_RESIDUE}, result::Ref{Cbool})
    ccall((:chfl_topology_residues_linked, libchemfiles), chfl_status, (Ptr{CHFL_TOPOLOGY}, Ptr{CHFL_RESIDUE}, Ptr{CHFL_RESIDUE}, Ref{Cbool}), topology, first, second, result)
end

# Function 'chfl_topology_free' at topology.h:233
function chfl_topology_free(topology::Ptr{CHFL_TOPOLOGY})
    ccall((:chfl_topology_free, libchemfiles), chfl_status, (Ptr{CHFL_TOPOLOGY},), topology)
end

# Function 'chfl_cell' at cell.h:33
function chfl_cell(lengths::chfl_vector3d)
    ccall((:chfl_cell, libchemfiles), Ptr{CHFL_CELL}, (Ptr{Float64},), lengths)
end

# Function 'chfl_cell_triclinic' at cell.h:50
function chfl_cell_triclinic(lengths::chfl_vector3d, angles::chfl_vector3d)
    ccall((:chfl_cell_triclinic, libchemfiles), Ptr{CHFL_CELL}, (Ptr{Float64}, Ptr{Float64}), lengths, angles)
end

# Function 'chfl_cell_from_frame' at cell.h:62
function chfl_cell_from_frame(frame::Ptr{CHFL_FRAME})
    ccall((:chfl_cell_from_frame, libchemfiles), Ptr{CHFL_CELL}, (Ptr{CHFL_FRAME},), frame)
end

# Function 'chfl_cell_copy' at cell.h:72
function chfl_cell_copy(cell::Ptr{CHFL_CELL})
    ccall((:chfl_cell_copy, libchemfiles), Ptr{CHFL_CELL}, (Ptr{CHFL_CELL},), cell)
end

# Function 'chfl_cell_volume' at cell.h:79
function chfl_cell_volume(cell::Ptr{CHFL_CELL}, volume::Ref{Cdouble})
    ccall((:chfl_cell_volume, libchemfiles), chfl_status, (Ptr{CHFL_CELL}, Ref{Cdouble}), cell, volume)
end

# Function 'chfl_cell_lengths' at cell.h:88
function chfl_cell_lengths(cell::Ptr{CHFL_CELL}, lengths::chfl_vector3d)
    ccall((:chfl_cell_lengths, libchemfiles), chfl_status, (Ptr{CHFL_CELL}, Ptr{Float64}), cell, lengths)
end

# Function 'chfl_cell_set_lengths' at cell.h:99
function chfl_cell_set_lengths(cell::Ptr{CHFL_CELL}, lengths::chfl_vector3d)
    ccall((:chfl_cell_set_lengths, libchemfiles), chfl_status, (Ptr{CHFL_CELL}, Ptr{Float64}), cell, lengths)
end

# Function 'chfl_cell_angles' at cell.h:108
function chfl_cell_angles(cell::Ptr{CHFL_CELL}, angles::chfl_vector3d)
    ccall((:chfl_cell_angles, libchemfiles), chfl_status, (Ptr{CHFL_CELL}, Ptr{Float64}), cell, angles)
end

# Function 'chfl_cell_set_angles' at cell.h:121
function chfl_cell_set_angles(cell::Ptr{CHFL_CELL}, angles::chfl_vector3d)
    ccall((:chfl_cell_set_angles, libchemfiles), chfl_status, (Ptr{CHFL_CELL}, Ptr{Float64}), cell, angles)
end

# Function 'chfl_cell_matrix' at cell.h:139
function chfl_cell_matrix(cell::Ptr{CHFL_CELL}, matrix::Ptr{Cdouble})
    ccall((:chfl_cell_matrix, libchemfiles), chfl_status, (Ptr{CHFL_CELL}, Ptr{Cdouble}), cell, matrix)
end

# Function 'chfl_cell_shape' at cell.h:148
function chfl_cell_shape(cell::Ptr{CHFL_CELL}, shape::Ref{chfl_cellshape})
    ccall((:chfl_cell_shape, libchemfiles), chfl_status, (Ptr{CHFL_CELL}, Ref{chfl_cellshape}), cell, shape)
end

# Function 'chfl_cell_set_shape' at cell.h:157
function chfl_cell_set_shape(cell::Ptr{CHFL_CELL}, shape::chfl_cellshape)
    ccall((:chfl_cell_set_shape, libchemfiles), chfl_status, (Ptr{CHFL_CELL}, chfl_cellshape), cell, shape)
end

# Function 'chfl_cell_wrap' at cell.h:166
function chfl_cell_wrap(cell::Ptr{CHFL_CELL}, vector::chfl_vector3d)
    ccall((:chfl_cell_wrap, libchemfiles), chfl_status, (Ptr{CHFL_CELL}, Ptr{Float64}), cell, vector)
end

# Function 'chfl_cell_free' at cell.h:174
function chfl_cell_free(cell::Ptr{CHFL_CELL})
    ccall((:chfl_cell_free, libchemfiles), chfl_status, (Ptr{CHFL_CELL},), cell)
end

# Function 'chfl_frame' at frame.h:20
function chfl_frame()
    ccall((:chfl_frame, libchemfiles), Ptr{CHFL_FRAME}, (), )
end

# Function 'chfl_frame_copy' at frame.h:30
function chfl_frame_copy(frame::Ptr{CHFL_FRAME})
    ccall((:chfl_frame_copy, libchemfiles), Ptr{CHFL_FRAME}, (Ptr{CHFL_FRAME},), frame)
end

# Function 'chfl_frame_atoms_count' at frame.h:38
function chfl_frame_atoms_count(frame::Ptr{CHFL_FRAME}, size::Ref{UInt64})
    ccall((:chfl_frame_atoms_count, libchemfiles), chfl_status, (Ptr{CHFL_FRAME}, Ref{UInt64}), frame, size)
end

# Function 'chfl_frame_positions' at frame.h:57
function chfl_frame_positions(frame::Ptr{CHFL_FRAME}, positions::Ref{Ptr{Cdouble}}, size::Ref{UInt64})
    ccall((:chfl_frame_positions, libchemfiles), chfl_status, (Ptr{CHFL_FRAME}, Ref{Ptr{Cdouble}}, Ref{UInt64}), frame, positions, size)
end

# Function 'chfl_frame_velocities' at frame.h:80
function chfl_frame_velocities(frame::Ptr{CHFL_FRAME}, velocities::Ref{Ptr{Cdouble}}, size::Ref{UInt64})
    ccall((:chfl_frame_velocities, libchemfiles), chfl_status, (Ptr{CHFL_FRAME}, Ref{Ptr{Cdouble}}, Ref{UInt64}), frame, velocities, size)
end

# Function 'chfl_frame_add_atom' at frame.h:92
function chfl_frame_add_atom(frame::Ptr{CHFL_FRAME}, atom::Ptr{CHFL_ATOM}, position::chfl_vector3d, velocity::chfl_vector3d)
    ccall((:chfl_frame_add_atom, libchemfiles), chfl_status, (Ptr{CHFL_FRAME}, Ptr{CHFL_ATOM}, Ptr{Float64}, Ptr{Float64}), frame, atom, position, velocity)
end

# Function 'chfl_frame_remove' at frame.h:105
function chfl_frame_remove(frame::Ptr{CHFL_FRAME}, i::UInt64)
    ccall((:chfl_frame_remove, libchemfiles), chfl_status, (Ptr{CHFL_FRAME}, UInt64), frame, i)
end

# Function 'chfl_frame_resize' at frame.h:117
function chfl_frame_resize(frame::Ptr{CHFL_FRAME}, size::UInt64)
    ccall((:chfl_frame_resize, libchemfiles), chfl_status, (Ptr{CHFL_FRAME}, UInt64), frame, size)
end

# Function 'chfl_frame_add_velocities' at frame.h:129
function chfl_frame_add_velocities(frame::Ptr{CHFL_FRAME})
    ccall((:chfl_frame_add_velocities, libchemfiles), chfl_status, (Ptr{CHFL_FRAME},), frame)
end

# Function 'chfl_frame_has_velocities' at frame.h:137
function chfl_frame_has_velocities(frame::Ptr{CHFL_FRAME}, has_velocities::Ref{Cbool})
    ccall((:chfl_frame_has_velocities, libchemfiles), chfl_status, (Ptr{CHFL_FRAME}, Ref{Cbool}), frame, has_velocities)
end

# Function 'chfl_frame_set_cell' at frame.h:146
function chfl_frame_set_cell(frame::Ptr{CHFL_FRAME}, cell::Ptr{CHFL_CELL})
    ccall((:chfl_frame_set_cell, libchemfiles), chfl_status, (Ptr{CHFL_FRAME}, Ptr{CHFL_CELL}), frame, cell)
end

# Function 'chfl_frame_set_topology' at frame.h:158
function chfl_frame_set_topology(frame::Ptr{CHFL_FRAME}, topology::Ptr{CHFL_TOPOLOGY})
    ccall((:chfl_frame_set_topology, libchemfiles), chfl_status, (Ptr{CHFL_FRAME}, Ptr{CHFL_TOPOLOGY}), frame, topology)
end

# Function 'chfl_frame_step' at frame.h:168
function chfl_frame_step(frame::Ptr{CHFL_FRAME}, step::Ref{UInt64})
    ccall((:chfl_frame_step, libchemfiles), chfl_status, (Ptr{CHFL_FRAME}, Ref{UInt64}), frame, step)
end

# Function 'chfl_frame_set_step' at frame.h:177
function chfl_frame_set_step(frame::Ptr{CHFL_FRAME}, step::UInt64)
    ccall((:chfl_frame_set_step, libchemfiles), chfl_status, (Ptr{CHFL_FRAME}, UInt64), frame, step)
end

# Function 'chfl_frame_guess_topology' at frame.h:189
function chfl_frame_guess_topology(frame::Ptr{CHFL_FRAME})
    ccall((:chfl_frame_guess_topology, libchemfiles), chfl_status, (Ptr{CHFL_FRAME},), frame)
end

# Function 'chfl_frame_distance' at frame.h:198
function chfl_frame_distance(frame::Ptr{CHFL_FRAME}, i::UInt64, j::UInt64, distance::Ref{Cdouble})
    ccall((:chfl_frame_distance, libchemfiles), chfl_status, (Ptr{CHFL_FRAME}, UInt64, UInt64, Ref{Cdouble}), frame, i, j, distance)
end

# Function 'chfl_frame_angle' at frame.h:209
function chfl_frame_angle(frame::Ptr{CHFL_FRAME}, i::UInt64, j::UInt64, k::UInt64, angle::Ref{Cdouble})
    ccall((:chfl_frame_angle, libchemfiles), chfl_status, (Ptr{CHFL_FRAME}, UInt64, UInt64, UInt64, Ref{Cdouble}), frame, i, j, k, angle)
end

# Function 'chfl_frame_dihedral' at frame.h:220
function chfl_frame_dihedral(frame::Ptr{CHFL_FRAME}, i::UInt64, j::UInt64, k::UInt64, m::UInt64, dihedral::Ref{Cdouble})
    ccall((:chfl_frame_dihedral, libchemfiles), chfl_status, (Ptr{CHFL_FRAME}, UInt64, UInt64, UInt64, UInt64, Ref{Cdouble}), frame, i, j, k, m, dihedral)
end

# Function 'chfl_frame_out_of_plane' at frame.h:234
function chfl_frame_out_of_plane(frame::Ptr{CHFL_FRAME}, i::UInt64, j::UInt64, k::UInt64, m::UInt64, distance::Ref{Cdouble})
    ccall((:chfl_frame_out_of_plane, libchemfiles), chfl_status, (Ptr{CHFL_FRAME}, UInt64, UInt64, UInt64, UInt64, Ref{Cdouble}), frame, i, j, k, m, distance)
end

# Function 'chfl_frame_set_property' at frame.h:246
function chfl_frame_set_property(frame::Ptr{CHFL_FRAME}, name::Ptr{UInt8}, property::Ptr{CHFL_PROPERTY})
    ccall((:chfl_frame_set_property, libchemfiles), chfl_status, (Ptr{CHFL_FRAME}, Ptr{UInt8}, Ptr{CHFL_PROPERTY}), frame, name, property)
end

# Function 'chfl_frame_get_property' at frame.h:260
function chfl_frame_get_property(frame::Ptr{CHFL_FRAME}, name::Ptr{UInt8})
    ccall((:chfl_frame_get_property, libchemfiles), Ptr{CHFL_PROPERTY}, (Ptr{CHFL_FRAME}, Ptr{UInt8}), frame, name)
end

# Function 'chfl_frame_add_bond' at frame.h:269
function chfl_frame_add_bond(frame::Ptr{CHFL_FRAME}, i::UInt64, j::UInt64)
    ccall((:chfl_frame_add_bond, libchemfiles), chfl_status, (Ptr{CHFL_FRAME}, UInt64, UInt64), frame, i, j)
end

# Function 'chfl_frame_remove_bond' at frame.h:281
function chfl_frame_remove_bond(frame::Ptr{CHFL_FRAME}, i::UInt64, j::UInt64)
    ccall((:chfl_frame_remove_bond, libchemfiles), chfl_status, (Ptr{CHFL_FRAME}, UInt64, UInt64), frame, i, j)
end

# Function 'chfl_frame_add_residue' at frame.h:293
function chfl_frame_add_residue(frame::Ptr{CHFL_FRAME}, residue::Ptr{CHFL_RESIDUE})
    ccall((:chfl_frame_add_residue, libchemfiles), chfl_status, (Ptr{CHFL_FRAME}, Ptr{CHFL_RESIDUE}), frame, residue)
end

# Function 'chfl_frame_free' at frame.h:301
function chfl_frame_free(frame::Ptr{CHFL_FRAME})
    ccall((:chfl_frame_free, libchemfiles), chfl_status, (Ptr{CHFL_FRAME},), frame)
end

# Function 'chfl_trajectory_open' at trajectory.h:22
function chfl_trajectory_open(path::Ptr{UInt8}, mode::Cchar)
    ccall((:chfl_trajectory_open, libchemfiles), Ptr{CHFL_TRAJECTORY}, (Ptr{UInt8}, Cchar), path, mode)
end

# Function 'chfl_trajectory_with_format' at trajectory.h:39
function chfl_trajectory_with_format(path::Ptr{UInt8}, mode::Cchar, format::Ptr{UInt8})
    ccall((:chfl_trajectory_with_format, libchemfiles), Ptr{CHFL_TRAJECTORY}, (Ptr{UInt8}, Cchar, Ptr{UInt8}), path, mode, format)
end

# Function 'chfl_trajectory_read' at trajectory.h:51
function chfl_trajectory_read(trajectory::Ptr{CHFL_TRAJECTORY}, frame::Ptr{CHFL_FRAME})
    ccall((:chfl_trajectory_read, libchemfiles), chfl_status, (Ptr{CHFL_TRAJECTORY}, Ptr{CHFL_FRAME}), trajectory, frame)
end

# Function 'chfl_trajectory_read_step' at trajectory.h:63
function chfl_trajectory_read_step(trajectory::Ptr{CHFL_TRAJECTORY}, step::UInt64, frame::Ptr{CHFL_FRAME})
    ccall((:chfl_trajectory_read_step, libchemfiles), chfl_status, (Ptr{CHFL_TRAJECTORY}, UInt64, Ptr{CHFL_FRAME}), trajectory, step, frame)
end

# Function 'chfl_trajectory_write' at trajectory.h:72
function chfl_trajectory_write(trajectory::Ptr{CHFL_TRAJECTORY}, frame::Ptr{CHFL_FRAME})
    ccall((:chfl_trajectory_write, libchemfiles), chfl_status, (Ptr{CHFL_TRAJECTORY}, Ptr{CHFL_FRAME}), trajectory, frame)
end

# Function 'chfl_trajectory_set_topology' at trajectory.h:83
function chfl_trajectory_set_topology(trajectory::Ptr{CHFL_TRAJECTORY}, topology::Ptr{CHFL_TOPOLOGY})
    ccall((:chfl_trajectory_set_topology, libchemfiles), chfl_status, (Ptr{CHFL_TRAJECTORY}, Ptr{CHFL_TOPOLOGY}), trajectory, topology)
end

# Function 'chfl_trajectory_topology_file' at trajectory.h:97
function chfl_trajectory_topology_file(trajectory::Ptr{CHFL_TRAJECTORY}, path::Ptr{UInt8}, format::Ptr{UInt8})
    ccall((:chfl_trajectory_topology_file, libchemfiles), chfl_status, (Ptr{CHFL_TRAJECTORY}, Ptr{UInt8}, Ptr{UInt8}), trajectory, path, format)
end

# Function 'chfl_trajectory_set_cell' at trajectory.h:107
function chfl_trajectory_set_cell(trajectory::Ptr{CHFL_TRAJECTORY}, cell::Ptr{CHFL_CELL})
    ccall((:chfl_trajectory_set_cell, libchemfiles), chfl_status, (Ptr{CHFL_TRAJECTORY}, Ptr{CHFL_CELL}), trajectory, cell)
end

# Function 'chfl_trajectory_nsteps' at trajectory.h:117
function chfl_trajectory_nsteps(trajectory::Ptr{CHFL_TRAJECTORY}, nsteps::Ref{UInt64})
    ccall((:chfl_trajectory_nsteps, libchemfiles), chfl_status, (Ptr{CHFL_TRAJECTORY}, Ref{UInt64}), trajectory, nsteps)
end

# Function 'chfl_trajectory_close' at trajectory.h:128
function chfl_trajectory_close(trajectory::Ptr{CHFL_TRAJECTORY})
    ccall((:chfl_trajectory_close, libchemfiles), chfl_status, (Ptr{CHFL_TRAJECTORY},), trajectory)
end

# Function 'chfl_selection' at selection.h:20
function chfl_selection(selection::Ptr{UInt8})
    ccall((:chfl_selection, libchemfiles), Ptr{CHFL_SELECTION}, (Ptr{UInt8},), selection)
end

# Function 'chfl_selection_copy' at selection.h:33
function chfl_selection_copy(selection::Ptr{CHFL_SELECTION})
    ccall((:chfl_selection_copy, libchemfiles), Ptr{CHFL_SELECTION}, (Ptr{CHFL_SELECTION},), selection)
end

# Function 'chfl_selection_size' at selection.h:45
function chfl_selection_size(selection::Ptr{CHFL_SELECTION}, size::Ref{UInt64})
    ccall((:chfl_selection_size, libchemfiles), chfl_status, (Ptr{CHFL_SELECTION}, Ref{UInt64}), selection, size)
end

# Function 'chfl_selection_string' at selection.h:58
function chfl_selection_string(selection::Ptr{CHFL_SELECTION}, string::Ptr{UInt8}, buffsize::UInt64)
    ccall((:chfl_selection_string, libchemfiles), chfl_status, (Ptr{CHFL_SELECTION}, Ptr{UInt8}, UInt64), selection, string, buffsize)
end

# Function 'chfl_selection_evaluate' at selection.h:71
function chfl_selection_evaluate(selection::Ptr{CHFL_SELECTION}, frame::Ptr{CHFL_FRAME}, n_matches::Ref{UInt64})
    ccall((:chfl_selection_evaluate, libchemfiles), chfl_status, (Ptr{CHFL_SELECTION}, Ptr{CHFL_FRAME}, Ref{UInt64}), selection, frame, n_matches)
end

# Function 'chfl_selection_matches' at selection.h:97
function chfl_selection_matches(selection::Ptr{CHFL_SELECTION}, matches::Ptr{chfl_match}, n_matches::UInt64)
    ccall((:chfl_selection_matches, libchemfiles), chfl_status, (Ptr{CHFL_SELECTION}, Ptr{chfl_match}, UInt64), selection, matches, n_matches)
end

# Function 'chfl_selection_free' at selection.h:105
function chfl_selection_free(selection::Ptr{CHFL_SELECTION})
    ccall((:chfl_selection_free, libchemfiles), chfl_status, (Ptr{CHFL_SELECTION},), selection)
end


text:
# # An equation of second order in two dimmensions
#
# Let \\(\Omega = (0, 1)^2\\) the unit square and denote \\( \Gamma = \partial \Omega\\) its boundary.
# Consider the following problem. Given \\(f \in C(\Omega)\\), find a function \\(u\\) satisfying
# \Delta^2 u = f in \Omega
# u = \Delta u = 0 on \Gamma

using Revise
using SymFEL
using LinearAlgebra
using SparseArrays
using WriteVTK
using JLD2

## discretization parameters
# we use the mesh square.msh (in gmsh format)
# obtained from square.geo using gmsh
# this mesh is formed by quad elements
# we use gmsh module for read the mesh
# there are some problems using Threads and gmsh (in linux)
# the file is square.jld2 is prepared separetely
@load "square-simple.jld2"

# elementary matrices - P2 x P2
elem_M = SymFEL.get_square_hermite_em((3, 3), (0, 0), (0, 0))
elem_K = SymFEL.get_square_hermite_em((3, 3), (2, 0), (2, 0)) +
    SymFEL.get_square_hermite_em((3, 3), (2, 0), (0, 2)) +
    SymFEL.get_square_hermite_em((3, 3), (0, 2), (2, 0)) +
    SymFEL.get_square_hermite_em((3, 3), (0, 2), (0, 2))

dx = norm(nodes_coordinate[:, elements_bound[1,1]] - nodes_coordinate[:, elements_bound[2,1]])
elem_K_dx = convert(Matrix{Float64}, elem_K.subs(h, dx))
elem_M_dx = convert(Matrix{Float64}, elem_M.subs(h, dx));

# global matrices
K = SymFEL.assemble_squaremesh_FE_matrix(elem_K_dx, elements_int,
                                           order1=1, order2=1,
                                           dof1=4, dof2=4)
M = SymFEL.assemble_squaremesh_FE_matrix(elem_M_dx, elements_int,
                                           order1=1, order2 = 1,
                                           dof1=4, dof2=4)

f = zeros(Float64, 4*nodes_N)
f[4*((1:nodes_N) .- 1) .+ 1] = 4*pi^4*sin.(pi * nodes_coordinate[1,:]) .* sin.(pi * nodes_coordinate[2,:])
f[4*((1:nodes_N) .- 1) .+ 2] = 4*pi^5*cos.(pi * nodes_coordinate[1,:]) .* sin.(pi * nodes_coordinate[2,:])
f[4*((1:nodes_N) .- 1) .+ 3] = 4*pi^5*sin.(pi * nodes_coordinate[1,:]) .* cos.(pi * nodes_coordinate[2,:])
f[4*((1:nodes_N) .- 1) .+ 4] = 4*pi^6*cos.(pi * nodes_coordinate[1,:]) .* cos.(pi * nodes_coordinate[2,:])

F = M * f

F[4*(nodes_boundary.-1).+1] = zeros(nodes_boundary_N)
A = copy(K)

# boundary condition
tgv = 1e30
A[4*(nodes_boundary.-1).+1, 4*(nodes_boundary.-1).+1] += tgv * sparse(Matrix{Float64}(I, nodes_boundary_N, nodes_boundary_N))

u = A \ F
u_exact = zeros(Float64, 4*nodes_N)
u_exact[4*((1:nodes_N) .- 1) .+ 1] = sin.(pi * nodes_coordinate[1,:]) .* sin.(pi * nodes_coordinate[2,:])
u_exact[4*((1:nodes_N) .- 1) .+ 2] = pi * cos.(pi * nodes_coordinate[1,:]) .* sin.(pi * nodes_coordinate[2,:])
u_exact[4*((1:nodes_N) .- 1) .+ 3] = pi * sin.(pi * nodes_coordinate[1,:]) .* cos.(pi * nodes_coordinate[2,:])
u_exact[4*((1:nodes_N) .- 1) .+ 4] = pi^2 * cos.(pi * nodes_coordinate[1,:]) .* cos.(pi * nodes_coordinate[2,:])

err = u - u_exact

println("L2 error : ", sqrt(err' * M * err))
println("H2 error : ", sqrt(err' * K * err))

# export to vtk
cells = [MeshCell(VTKCellTypes.VTK_QUAD, elements_int[1:4, i]) for i = 1:elements_int_N]

points_x = nodes_coordinate[1, :]
points_y = nodes_coordinate[2, :]
vtkfile = vtk_grid("ex4-output", points_x, points_y, cells)

vtkfile["u", VTKPointData()] = u[4*((1:nodes_N) .- 1) .+ 1]
vtkfile["ux", VTKPointData()] = u[4*((1:nodes_N) .- 1) .+ 2]
vtkfile["uy", VTKPointData()] = u[4*((1:nodes_N) .- 1) .+ 3]
vtkfile["uxy", VTKPointData()] = u[4*((1:nodes_N) .- 1) .+ 4]
outfiles = vtk_save(vtkfile)

ext: jl


text:
#
# Copyright (c) 2021 Tobias Thummerer, Lars Mikelsons, Josef Kircher
# Licensed under the MIT license. See LICENSE file in the project root for details.
#

import FMIImport: fmi2StatusError, fmi2StatusOK

myFMU = fmi2Load("SpringPendulum1D", ENV["EXPORTINGTOOL"], ENV["EXPORTINGVERSION"])
myFMU.executionConfig.assertOnWarning = true

### CASE A: Print log ###
comp = fmi2Instantiate!(myFMU; loggingOn=true)
@test comp != 0

open(joinpath(pwd(), "stdout"), "w") do out
    open(joinpath(pwd(), "stderr"), "w") do err
        redirect_stdout(out) do
            redirect_stderr(err) do
                @test fmi2SetupExperiment(comp) == fmi2StatusOK
            end
        end
    end
end
# ToDo: this test is wrong / not working (capture doesn't work for color output)
#output = read(joinpath(pwd(), "stdout"), String)
#@test output == ""
#output = read(joinpath(pwd(), "stderr"), String)
#@test output == ""

### CASE B: Print log, but catch infos ###

comp = fmi2Instantiate!(myFMU; loggingOn=true, logStatusError=false)
@test comp != 0

# # deactivate errors to capture them
# assertOnError = myFMU.executionConfig.assertOnError
# myFMU.executionConfig.assertOnError = false

open(joinpath(pwd(), "stdout"), "w") do out
    open(joinpath(pwd(), "stderr"), "w") do err
        redirect_stdout(out) do
            redirect_stderr(err) do
                @test fmi2SetupExperiment(comp) == fmi2StatusOK
            end
        end
    end
end

# # reenable errors
# myFMU.executionConfig.assertOnError = assertOnError

# output = read(joinpath(pwd(), "stdout"), String)
# @test output == ""
# output = read(joinpath(pwd(), "stderr"), String)
# @test output == ""

### CASE C: Disable Log ###

comp = fmi2Instantiate!(myFMU; loggingOn=false)
@test comp != 0

open(joinpath(pwd(), "stdout"), "w") do out
    open(joinpath(pwd(), "stderr"), "w") do err
        redirect_stdout(out) do
            redirect_stderr(err) do
                @test fmi2SetupExperiment(comp) == fmi2StatusOK
            end
        end
    end
end
# ToDo: this test is wrong / not working (capture doesn't work for color output)
#output = read(joinpath(pwd(), "stdout"), String)
#@test output == ""
#output = read(joinpath(pwd(), "stderr"), String)
#@test output == ""

# cleanup
fmi2Unload(myFMU)


text:
# This file is a part of Julia. License is MIT: https://julialang.org/license

using Test
import REPL
import Markdown

@testset "symbol completion" begin
    @test startswith(let buf = IOBuffer()
            Core.eval(Main, REPL.helpmode(buf, "α"))
            String(take!(buf))
        end, "\"α\" can be typed by \\alpha<tab>\n")

    @test startswith(let buf = IOBuffer()
            Core.eval(Main, REPL.helpmode(buf, "🐨"))
            String(take!(buf))
        end, "\"🐨\" can be typed by \\:koala:<tab>\n")
end

@testset "Non-Markdown" begin
    @test isa(REPL.insert_hlines(IOBuffer(), Markdown.Text("foo")), Markdown.Text)
end

max_stars_repo_name: shikhargoswami/julia

max_issues_repo_name: shikhargoswami/julia

max_forks_repo_name: shikhargoswami/julia


text:
__precompile__(false)
module BulletCollision

using Cxx
using GeometryTypes
using StaticArrays
using Libdl
using LinearAlgebra

include("load_bullet.jl")

### type definitions
const BulletCollisionObjectPtr  = @cxxt_str "btCollisionObject*"
const BulletCollisionShapePtr   = @cxxt_str "btCollisionShape*"
const BulletConvexShapePtr      = @cxxt_str "btConvexShape*"
const BulletCompoundShapePtr    = @cxxt_str "btCompoundShape*"
const BulletCollisionWorldPtr   = @cxxt_str "btCollisionWorld*"
const BulletTransformPtr        = @cxxt_str "btTransform*"
const BulletTransformValue      = @cxxt_str "btTransform"
const BulletScalar              = @cxxt_str "btScalar"
const BulletMultiBodyPtr        = @cxxt_str "btMultiBody*"
const BulletInf = icxx"""BT_LARGE_FLOAT;""";

set_margin(obj::BulletCollisionObjectPtr, dx = 0.) = set_margin(get_collision_shape(obj), dx)

function set_margin(cs::BulletCollisionShapePtr, dx = 0.)
  if icxx"""$cs->isConvex();"""
    icxx"""$cs->setMargin($dx);"""
  elseif icxx"""$cs->isCompound();"""
    cs = icxx"""btCompoundShape* cm = (btCompoundShape*)$cs; cm;"""
    num_children = icxx"""$cs->getNumChildShapes();"""
    for i in 0:num_children-1
      set_margin(icxx"""$cs->getChildShape($i);""", dx)
    end
  end
end

get_collision_shape(obj::BulletCollisionObjectPtr) = icxx"""$obj->getCollisionShape();"""
get_world_transform(obj::BulletCollisionObjectPtr) = icxx"""btTransform tr = $obj->getWorldTransform(); tr;"""
identity_transform() = icxx"""btTransform tr; tr.setIdentity(); tr;"""

### primitive shapes
function box(lo::AbstractVector, hi::AbstractVector)
  halfextents = (hi - lo)/2
  mid = (hi + lo)/2
  icxx"""
  btCollisionObject* box = new btCollisionObject();
  btBoxShape* box_shape = new btBoxShape(btVector3($(halfextents[1]), $(halfextents[2]), $(halfextents[3])));
  box_shape->setMargin(0.);
  box->getWorldTransform().setOrigin(btVector3($(mid[1]), $(mid[2]), $(mid[3])));
  box->setCollisionShape(box_shape);
  box;
  """
end

function convex_hull(pts::Vector{V}) where V <: AbstractVector
  convex_hull = icxx"""
  btCollisionObject* convex_hull = new btCollisionObject();
  btConvexHullShape* convex_hull_shape = new btConvexHullShape();
  convex_hull_shape->setMargin(0.);
  convex_hull->getWorldTransform().setIdentity();
  convex_hull->setCollisionShape(convex_hull_shape);
  convex_hull;
  """
  for v in pts
    icxx"""((btConvexHullShape*)($convex_hull->getCollisionShape()))->addPoint(btVector3($(v[1]), $(v[2]), $(v[3])));"""
  end
  convex_hull
end

convex_hull(pts::V...) where V <: AbstractVector = convex_hull(collect(pts))
geometry_type_to_BT(shape::HomogenousMesh) = convex_hull(shape.vertices)
convex_hull_box(lo::AbstractVector, hi::AbstractVector) = convex_hull([SVector{3}([lo hi][[1,2,3] + 3*[i,j,k]]) for i=0:1, j=0:1, k=0:1]...)

function geometry_type_to_BT(shape::HyperRectangle,hull::Bool=true)
  if hull
    return convex_hull_box(SVector{3}(shape.origin),shape.origin+shape.widths)
  end
  return box(SVector{3}(shape.origin),shape.origin+shape.widths)
end

function convex_hull_cylinder(p1::AbstractVector, p2::AbstractVector, r::AbstractFloat, n::Int=25)
  Q, _ = LinearAlgebra.qr(reshape(p2-p1,(3,1)))
  #Q, _ = qr((p2-p1)'', thin=false) # Ed's code
  d1, d2 = Q[:,2], Q[:,3]
  convex_hull((p1 + r*cos(2*pi*i/n)*d1 + r*sin(2*pi*i/n)*d2 for i in 1:n)...,
              (p2 + r*cos(2*pi*i/n)*d1 + r*sin(2*pi*i/n)*d2 for i in 1:n)...)
end

geometry_type_to_BT(shape::Cylinder) = convex_hull_cylinder(SVector{3}(shape.origin), SVector{3}(shape.origin+shape.extremity), shape.r)

function sphere(c::AbstractVector, r::AbstractFloat)
  icxx"""
  btCollisionObject* sphere = new btCollisionObject();
  btSphereShape* sphere_shape = new btSphereShape($r);
  sphere_shape->setMargin(0.);
  sphere->getWorldTransform().setOrigin(btVector3($(c[1]), $(c[2]), $(c[3])));
  sphere->setCollisionShape(sphere_shape);
  sphere;
  """
end

geometry_type_to_BT(shape::HyperSphere) = sphere(SVector{3}(shape.center),shape.r)

### concave shape made out of convex sub parts called child shapes
### each child shape has its own local offset transform relative to bBulletCompoundShapePtrtCompoundShape
function compound_collision_object(objs::Vector{BulletCollisionObjectPtr})
  compound = icxx"""
  btCollisionObject* compound = new btCollisionObject();
  btCompoundShape* compound_shape = new btCompoundShape(true, $(length(objs)));
  compound_shape->setMargin(0.);
  compound->getWorldTransform().setIdentity();
  compound->setCollisionShape(compound_shape);
  compound;
  """
  for o in objs
    icxx"""((btCompoundShape*)($compound->getCollisionShape()))->addChildShape($o->getWorldTransform(),
                                                                                $o->getCollisionShape());"""
  end
  icxx"""((btCompoundShape*)($compound->getCollisionShape()))->recalculateLocalAabb();"""
  compound
end

compound_collision_object(objs::BulletCollisionObjectPtr...) = compound_collision_object(collect(objs))

function make_2d(co::BulletCollisionObjectPtr)
  icxx"""
  btConvex2dShape* shape2d = new btConvex2dShape((btConvexShape*)($co->getCollisionShape()));
  shape2d->setMargin(0.);
  $co->setCollisionShape(shape2d);
  """
  co
end

#### distance between two btCollisionShape's (including compound shapes)
function distance(co1::BulletCollisionObjectPtr, co2::BulletCollisionObjectPtr, max_d2 = BulletInf)
    result_ptr = icxx"""
    btScalar* result = new btScalar[7];
    result[0] = btScalar(BT_LARGE_FLOAT);
    compute_distance($co1->getCollisionShape(), $co1->getWorldTransform(),
                     $co2->getCollisionShape(), $co2->getWorldTransform(),
                     result, $max_d2);
    result;
    """
    result = unsafe_load(convert(Ptr{SVector{7,Float32}}, result_ptr))
    icxx"""delete[] $result_ptr;"""
    result[1], result[2:4], result[5:7] # signed distance, point on co1, point on co2
end

### stores all btCollisionObjects and provides an interface to perform queries
function collision_world(lo::AbstractVector, hi::AbstractVector, maxobjects = 100)
  icxx"""
  btCollisionConfiguration* collision_configuration = new btDefaultCollisionConfiguration();
  btCollisionDispatcher* dispatcher = new btCollisionDispatcher(collision_configuration);

  btVector3 worldAabbMin($(lo[1]), $(lo[2]), $(lo[3]));
  btVector3 worldAabbMax($(hi[1]), $(hi[2]), $(hi[3]));
  unsigned int max_objects = $maxobjects;

  btBroadphaseInterface* broadphase = new btAxisSweep3(worldAabbMin, worldAabbMax, max_objects, 0, false);
  btCollisionWorld* cw = new btCollisionWorld(dispatcher, broadphase, collision_configuration);
  cw;
  """
end

get_convex_components(co::BulletCollisionObjectPtr) = get_convex_components(get_collision_shape(co), get_world_transform(co))

function get_convex_components(cs::BulletCollisionShapePtr, tr::BulletTransformValue = identity_transform())
  if icxx"""$cs->isConvex();"""
    [icxx"""btCollisionObject* cc = new btCollisionObject(); cc->setCollisionShape($cs); cc->setWorldTransform($tr); cc;"""]
  elseif icxx"""$cs->isCompound();"""
    cs = icxx"""btCompoundShape* cm = (btCompoundShape*)$cs; cm;"""
    num_children = icxx"""$cs->getNumChildShapes();"""
    vcat((get_convex_components(icxx"""$cs->getChildShape($i);""",
                                icxx"""btTransform comp = $tr * $cs->getChildTransform($i); comp;""")
          for i in 0:num_children-1)...)
  end
end

mutable struct BulletStaticEnvironment
  robot::BulletCollisionObjectPtr
  convex_robot_components::Vector{BulletCollisionObjectPtr}    # when robot's world transform is the identity; TODO(acauligi): set_transformation is unsafe
  environment::BulletCollisionWorldPtr
  convex_env_components::Vector{BulletCollisionObjectPtr}
  count::Int
end

function BulletStaticEnvironment(r::BulletCollisionObjectPtr, e::BulletCollisionWorldPtr)
  num_co = icxx"""$e->getNumCollisionObjects();"""
  e_components = vcat((get_convex_components(icxx"""(btCollisionObject *)($e->getCollisionObjectArray()[$i]);""") for i in 0:num_co-1)...)
  BulletStaticEnvironment(r, get_convex_components(get_collision_shape(r)), e, e_components, 0)
end

add_collision_object!(cw::BulletCollisionWorldPtr, co::BulletCollisionObjectPtr) =
    icxx"""$cw->addCollisionObject($co); $cw->updateAabbs();"""

function add_collision_object!(CC::BulletStaticEnvironment, co::BulletCollisionObjectPtr)
  add_collision_object!(CC.environment, co)
  append!(CC.convex_env_components, get_convex_components(co))
end

set_margin(CC::BulletStaticEnvironment, dx = 0.) = set_margin(CC.robot, dx)

function set_transformation(o::BulletCollisionObjectPtr, v::SVector{3})
  icxx"""$o->getWorldTransform().setOrigin(btVector3($(v[1]), $(v[2]), $(v[3])));"""
end

function set_transformation(o::BulletCollisionObjectPtr, v::SVector{4})
  icxx"""$o->getWorldTransform().setRotation(btQuaternion($(v[1]), $(v[2]), $(v[3]), $(v[4])));"""
end

function set_transformation(o::BulletCollisionObjectPtr, v::SVector{7})
  icxx"""
  $o->getWorldTransform().setOrigin(btVector3($(v[1]), $(v[2]), $(v[3])));
  $o->getWorldTransform().setRotation(btQuaternion($(v[4]), $(v[5]), $(v[6]), $(v[7])));
  """
end
set_transformation(o::BulletCollisionObjectPtr, v::AbstractVector) = set_transformation(o, SVector{length(v)}(v))

function is_free_state(v::SVector, CC::BulletStaticEnvironment)
  set_transformation(CC.robot, v)
  icxx"""
  BinaryCollisionCallback result;
  $(CC.environment)->contactTest($(CC.robot), result);
  !result.is_collision;
  """
end

function is_free_state(CC::BulletStaticEnvironment)
  icxx"""
  $(CC.environment)->performDiscreteCollisionDetection();
  int numManifolds = $(CC.environment)->getDispatcher()->getNumManifolds();
  bool is_free_state = true;
  //For each contact manifold
  for (int i = 0; i < numManifolds; i++) {
    btPersistentManifold* contactManifold = $(CC.environment)->getDispatcher()->getManifoldByIndexInternal(i);
    const btCollisionObject* obA = (contactManifold->getBody0());
    const btCollisionObject* obB = (contactManifold->getBody1());
    contactManifold->refreshContactPoints(obA->getWorldTransform(), obB->getWorldTransform());
    int numContacts = contactManifold->getNumContacts();
    if (numContacts > 0) {
      is_free_state = false;
      break;
    }
    ////For each contact point in that manifold
    //for (int j = 0; j < numContacts; j++) {
    //  //Get the contact information
    //    btManifoldPoint& pt = contactManifold->getContactPoint(j);
    //    btVector3 ptA = pt.getPositionWorldOnA();
    //    btVector3 ptB = pt.getPositionWorldOnB();
    //    double ptdist = pt.getDistance();
    //}
  }
  is_free_state;
  """
end

function is_free_motion(v::SVector{3}, w::SVector{3}, CC::BulletStaticEnvironment)
  CC.count += 1
  icxx"""
  bool free_motion = true;
  btCompoundShape* robot_compound = (btCompoundShape*) ($(CC.robot)->getCollisionShape());
  btTransform v, w;
  v.setIdentity();
  w.setIdentity();
  v.setOrigin(btVector3($(v[1]), $(v[2]), $(v[3])));
  w.setOrigin(btVector3($(w[1]), $(w[2]), $(w[3])));
  for (int i = 0; i < robot_compound->getNumChildShapes(); i++) {
    BinarySweptConvexCollisionCallback result;
    btConvexShape* robot_piece = (btConvexShape*) (robot_compound->getChildShape(i));
    $(CC.environment)->convexSweepTest(robot_piece, v * robot_compound->getChildTransform(i), w * robot_compound->getChildTransform(i), result);
    if (result.is_collision) {
      free_motion = false;
      break;
    }
  }
  free_motion;
  """
end

function is_free_motion(v::SVector{6}, w::SVector{6}, CC::BulletStaticEnvironment)
  CC.count += 1
  icxx"""
  bool free_motion = true;
  btCompoundShape* robot_compound = (btCompoundShape*) ($(CC.robot)->getCollisionShape());
  btTransform v, w;
  btQuaternion vrot, wrot;
  vrot.setEulerZYX($(v[4]), $(v[5]), $(v[6]));
  wrot.setEulerZYX($(w[4]), $(w[5]), $(w[6]));
  v.setOrigin(btVector3($(v[1]), $(v[2]), $(v[3])));
  w.setOrigin(btVector3($(w[1]), $(w[2]), $(w[3])));
  v.setRotation(vrot);
  w.setRotation(wrot);
  for (int i = 0; i < robot_compound->getNumChildShapes(); i++) {
    BinarySweptConvexCollisionCallback result;
    btConvexShape* robot_piece = (btConvexShape*) (robot_compound->getChildShape(i));
    $(CC.environment)->convexSweepTest(robot_piece, v * robot_compound->getChildTransform(i), w * robot_compound->getChildTransform(i), result);
    if (result.is_collision) {
      free_motion = false;
      break;
    }
  }
  free_motion;
  """
end

is_free_motion(v::AbstractVector, w::AbstractVector, CC::BulletStaticEnvironment) = is_free_motion(SVector(v), SVector(w), CC)

function distance(CC::BulletStaticEnvironment, ri::Int, tr::AbstractVector, ei::Int)
  rc, ec = CC.convex_robot_components[ri], CC.convex_env_components[ei]
  set_transformation(rc, tr)
  distance(rc, ec)
end

function distance_gradient_finite_difference(CC::BulletStaticEnvironment, ri::Int, tr::SVector{3,T}, ei::Int, dx::T = T(.01)) where T
    trm = MVector(tr)
    function gradi(i)
        tri = trm[i]
        trm[i] = tri + dx; fp = distance(CC, ri, trm, ei)[1]
        trm[i] = tri - dx; fm = distance(CC, ri, trm, ei)[1]
        trm[i] = tri
        (fp - fm) / (dx + dx)
    end
    SVector{3}([gradi(i) for i in 1:3])
end

function pairwise_convex_convex_distances(v::AbstractVector{T}, CC::BulletStaticEnvironment, threshold = T(Inf)) where T
  foreach(rc -> set_transformation(rc, v), CC.convex_robot_components)
  pairwise_iter = ((ri, ei, distance(rc, ec)) for (ri, rc) in enumerate(CC.convex_robot_components),
                                                  (ei, ec) in enumerate(CC.convex_env_components))
  collect(filter(x -> x[3][1] < threshold, pairwise_iter))    # note: filter must be collected now because of set_transformation
end

function pairwise_convex_convex_distances(v::AbstractVector{T}, CC::BulletStaticEnvironment, W::AbstractMatrix{T}, threshold = T(Inf)) where T
  foreach(rc -> set_transformation(rc, v), CC.convex_robot_components)
  pairwise_iter = ((ri, ei, distance(rc, ec, W)) for (ri, rc) in enumerate(CC.convex_robot_components),
                                                     (ei, ec) in enumerate(CC.convex_env_components))
  collect(filter(x -> x[3][1] < threshold, pairwise_iter))    # note: filter must be collected now because of set_transformation
end

end


text:
## Here are some utility functions

"""
    load_logdata!(df::Ref{DataFrame}, path) -> nothing

Loads the logfiles from the specified path into the `DataFrame` reference `df`.
All files with the `".log"` extension will be loaded. The resulting data frame
will have three columns: `:date`, `:temperature` and `:humidity`. If there are no
data to be read we put in some default values because other functionality relies
on data in the data frame.
"""
function load_logdata!(df::Ref{DataFrame}, path)
    df[] = DataFrame(date=DateTime[], temperature=Float64[], humidity=Float64[])

    for file in readdir(path)
        # skip file if it is not a .log file
        splitext(file)[2] ≠ ".log" && continue
        _df = CSV.read(joinpath(path, file), DataFrame; header=[:date, :temperature, :humidity])
        append!(df[], _df)
    end

    # There has to be data in the data frame in order to do statistics on it. If
    # we get an empty data frame, we put defaults in there so we don't get
    # errors.
    if isempty(df[])
        @warn "There is no data to plot"
        _df = DataFrame(date=now(), temperature=-300.0, humidity=-42.0)
        append!(df[], _df)
    end

    nothing
end

"""
    filter_dates(df::Ref{DataFrame}, start_date, end_date) -> DataFrame

Filters the `DataFrame` at `df::Ref{DataFrame}` so it returns only the part that
is in the range between `start_date` and `end_date`.
"""
filter_dates(df::Ref{DataFrame}, start_date, end_date) = filter(x -> start_date < x.date < end_date, df[])

"""
    update_figure!(fig, df, end_date) -> nothing

Appends data from `df` to the figure `fig` that were not already included in the
figure. Only data between the last date entry in the figure and `end_date` will
be appended.
"""
function update_figure!(fig, df, end_date)
    # if we get an empty figure we'll return right away
    isempty(fig[:data][1][:x]) && return

    # we have to append the data that was generated after the last update up
    # until the end_date
    last_date = fig[:data][1][:x][end] |> DateTime
    dff = filter_dates(df, last_date, end_date)

    append!(fig[:data][1][:x], dff.date)
    append!(fig[:data][1][:y], dff.temperature)
    append!(fig[:data][2][:x], dff.date)
    append!(fig[:data][2][:y], dff.humidity)

    nothing
end

"""
    replace_figure_data!(fig, df, (date_range)) -> nothing

This will replace the data in the figure `fig` with the data in `DataFrame`
reference `df` in the desired `date_range`. The date range should be given as
`(start_date, end_date)`.
"""
function replace_figure_data!(fig, df, (date_range))
    start_date, end_date = date_range
    dff = filter_dates(df, start_date, end_date)

    # since the data is stored in a named tuple we can only modify the data
    # inside the data arrays but not replace them. In order to achieve this, we
    # first delete all elements of the arrays and then append the new values.
    for (array, new_values) in zip(
        # the x and y arrays might be empty and may be passed as
        #   JSON3.Array{Union{}, Base.CodeUnits{UInt8, String}, SubArray{UInt64, 1, Vector{UInt64}, Tuple{UnitRange{Int64}}, true}}
        # we use `.|> Vector{Float64}` to convert them to an appropriate type
        # the `deleteat!` and `append!` function can work with.
        [fig[:data][1][:x], fig[:data][1][:y], fig[:data][2][:x], fig[:data][2][:y]],
        [string.(dff.date), dff.temperature, string.(dff.date), dff.humidity]
    )
        deleteat!(array, eachindex(array)) # removes all elements
        append!(array, new_values)
    end

    nothing
end

"""
    statistics(df::Ref{DataFrame}, column, date_range=(START_DATE, now())) ->
    Tuple{Float64,Float64,Float64}

Performs analysis on the data frame reference `df` for the specified `column` in
the specified `date_range`. It returns a `Tuple` where the entries are the `(mean,
min, max)` of the `column`. If the data frame at `df` is empty we return `0.0`s
as default values.
"""
function statistics(df::Ref{DataFrame}, column, date_range=(START_DATE, now()))
    # if there is no data in the dataframe return immeadiatly
    isempty(df[]) && return (mean=0.0, min=0.0, max=0.0)

    dff = filter_dates(df, date_range...)

    # if the dataframe is empty return some default values
    isempty(dff) && return (mean=0.0, min=0.0, max=0.0)

    min_val, max_val = extrema(dff[!, column])
    mean_val = mean(dff[!, column])
    (mean=mean_val, min=min_val, max=max_val)
end

"""
    generate_stats(stats, unit) --> DashHtmlComponents.Component

Returns a `html_div` component with the statistics text.
"""
function generate_stats(stats, unit)
    html_div() do
        html_p("Mean: $(round(stats.mean, digits=2)) $unit"),
        html_p("Max: $(round(stats.max, digits=2)) $unit"),
        html_p("Min: $(round(stats.min, digits=2)) $unit")
    end
end


text:
include("ppo_trajectory.jl")

using Random

export PPOLearner

"""
    PPOLearner(;kwargs)

# Keyword arguments

- `approximator`,
- `γ = 0.99f0`,
- `λ = 0.95f0`,
- `clip_range = 0.2f0`,
- `max_grad_norm = 0.5f0`,
- `n_microbatches = 4`,
- `n_epochs = 4`,
- `actor_loss_weight = 1.0f0`,
- `critic_loss_weight = 0.5f0`,
- `entropy_loss_weight = 0.01f0`,
- `rng = Random.GLOBAL_RNG`,
"""
mutable struct PPOLearner{A<:ActorCritic,R} <: AbstractLearner
    approximator::A
    γ::Float32
    λ::Float32
    clip_range::Float32
    max_grad_norm::Float32
    n_microbatches::Int
    n_epochs::Int
    actor_loss_weight::Float32
    critic_loss_weight::Float32
    entropy_loss_weight::Float32
    rng::R
    # for logging
    norm::Matrix{Float32}
    actor_loss::Matrix{Float32}
    critic_loss::Matrix{Float32}
    entropy_loss::Matrix{Float32}
    loss::Matrix{Float32}
end

function PPOLearner(;
    approximator,
    γ = 0.99f0,
    λ = 0.95f0,
    clip_range = 0.2f0,
    max_grad_norm = 0.5f0,
    n_microbatches = 4,
    n_epochs = 4,
    actor_loss_weight = 1.0f0,
    critic_loss_weight = 0.5f0,
    entropy_loss_weight = 0.01f0,
    rng = Random.GLOBAL_RNG,
)
    PPOLearner(
        approximator,
        γ,
        λ,
        clip_range,
        max_grad_norm,
        n_microbatches,
        n_epochs,
        actor_loss_weight,
        critic_loss_weight,
        entropy_loss_weight,
        rng,
        zeros(Float32, n_microbatches, n_epochs),
        zeros(Float32, n_microbatches, n_epochs),
        zeros(Float32, n_microbatches, n_epochs),
        zeros(Float32, n_microbatches, n_epochs),
        zeros(Float32, n_microbatches, n_epochs),
    )
end

function (learner::PPOLearner)(env::MultiThreadEnv)
    logits =
        learner.approximator.actor(send_to_device(
            device(learner.approximator),
            get_state(env),
        )) |> send_to_host

    if ActionStyle(env[1]) === FULL_ACTION_SET
        logits .+= typemin(eltype(logits)) .* (1 .- get_legal_actions_mask(env))
    end
    logits
end

function (learner::PPOLearner)(env)
    s = get_state(env)
    s = Flux.unsqueeze(s, ndims(s) + 1)
    s = send_to_device(device(learner.approximator), s)
    logits = learner.approximator.actor(s) |> vec |> send_to_host

    if ActionStyle(env) === FULL_ACTION_SET
        logits .+= typemin(eltype(logits)) .* (1 .- get_legal_actions_mask(env))
    end
    logits
end

function RLBase.update!(learner::PPOLearner, t::PPOTrajectory)
    isfull(t) || return

    states = t[:state]
    actions = t[:action]
    action_log_probs = t[:action_log_prob]
    rewards = t[:reward]
    terminals = t[:terminal]
    states_plus = t[:full_state]

    rng = learner.rng
    AC = learner.approximator
    γ = learner.γ
    λ = learner.λ
    n_epochs = learner.n_epochs
    n_microbatches = learner.n_microbatches
    clip_range = learner.clip_range
    w₁ = learner.actor_loss_weight
    w₂ = learner.critic_loss_weight
    w₃ = learner.entropy_loss_weight
    D = device(AC)

    n_envs, n_rollout = size(terminals)
    @assert n_envs * n_rollout % n_microbatches == 0 "size mismatch"
    microbatch_size = n_envs * n_rollout ÷ n_microbatches

    states_flatten = flatten_batch(states)
    states_plus_flatten = flatten_batch(states_plus)
    states_plus_values =
        reshape(send_to_host(AC.critic(send_to_device(D, states_plus_flatten))), n_envs, :)
    advantages =
        generalized_advantage_estimation(rewards, states_plus_values, γ, λ; dims = 2)
    returns = advantages .+ select_last_dim(states_plus_values, 1:n_rollout)

    # TODO: normalize advantage
    for epoch in 1:n_epochs
        rand_inds = shuffle!(rng, Vector(1:n_envs*n_rollout))
        for i in 1:n_microbatches
            inds = rand_inds[(i-1)*microbatch_size+1:i*microbatch_size]
            s = send_to_device(D, select_last_dim(states_flatten, inds))
            if haskey(t, :legal_actions_mask)
                lam = send_to_device(
                    D,
                    select_last_dim(flatten_batch(t[:legal_actions_mask]), inds),
                )
            end
            a = vec(actions)[inds]
            r = send_to_device(D, vec(returns)[inds])
            log_p = send_to_device(D, vec(action_log_probs)[inds])
            adv = send_to_device(D, vec(advantages)[inds])

            ps = Flux.params(AC)
            gs = gradient(ps) do
                v′ = AC.critic(s) |> vec
                logit′ = AC.actor(s)
                if haskey(t, :legal_actions_mask)
                    logit′ .+= typemin(eltype(logit′)) .* (1 .- lam)
                end
                p′ = softmax(logit′)
                log_p′ = logsoftmax(logit′)
                log_p′ₐ = log_p′[CartesianIndex.(a, 1:length(a))]

                ratio = exp.(log_p′ₐ .- log_p)
                surr1 = ratio .* adv
                surr2 = clamp.(ratio, 1.0f0 - clip_range, 1.0f0 + clip_range) .* adv

                actor_loss = -mean(min.(surr1, surr2))
                critic_loss = mean((r .- v′) .^ 2)
                entropy_loss = -sum(p′ .* log_p′) * 1 // size(p′, 2)
                loss = w₁ * actor_loss + w₂ * critic_loss - w₃ * entropy_loss

                ignore() do
                    learner.actor_loss[i, epoch] = actor_loss
                    learner.critic_loss[i, epoch] = critic_loss
                    learner.entropy_loss[i, epoch] = entropy_loss
                    learner.loss[i, epoch] = loss
                end

                loss
            end

            learner.norm[i, epoch] = clip_by_global_norm!(gs, ps, learner.max_grad_norm)
            update!(AC, gs)
        end
    end
end

function (π::QBasedPolicy{<:PPOLearner})(env::MultiThreadEnv)
    action_values = π.learner(env)
    logits = logsoftmax(action_values)
    actions = π.explorer(action_values)
    actions_log_prob = logits[CartesianIndex.(actions, 1:size(action_values, 2))]
    actions, actions_log_prob
end

(π::QBasedPolicy{<:PPOLearner})(env) = env |> π.learner |> π.explorer

function (p::RandomStartPolicy{<:QBasedPolicy{<:PPOLearner}})(env::MultiThreadEnv)
    p.num_rand_start -= 1
    if p.num_rand_start < 0
        p.policy(env)
    else
        a = p.random_policy(env)
        log_p = log.(get_prob(p.random_policy, env, a))
        a, log_p
    end
end

function (agent::Agent{<:AbstractPolicy,<:PPOTrajectory})(::Training{PreActStage}, env)
    action, action_log_prob = agent.policy(env)
    state = get_state(env)
    push!(
        agent.trajectory;
        state = state,
        action = action,
        action_log_prob = action_log_prob,
    )
    update!(agent.policy, agent.trajectory)

    # the main difference is we'd like to flush the buffer after each update!
    if isfull(agent.trajectory)
        empty!(agent.trajectory)
        push!(
            agent.trajectory;
            state = state,
            action = action,
            action_log_prob = action_log_prob,
        )
    end

    action
end

function (agent::Agent{<:AbstractPolicy,<:PPOTrajectory})(::Training{PostActStage}, env)
    push!(agent.trajectory; reward = get_reward(env), terminal = get_terminal(env))
    nothing
end

function (agent::Agent{<:AbstractPolicy,<:PPOTrajectory})(::Testing{PreActStage}, env)
    agent.policy(env)[1]  # ignore the log_prob of action
end


text:
using Distributed
addprocs(length(Sys.cpu_info())-1) # use all cores
@everywhere using CarrierCapture
@everywhere using NPZ
@everywhere using SharedArrays

# params
@everywhere a_i = 11.7442
@everywhere a_f = 4.71261
@everywhere b_i = 0.0147757
@everywhere b_f = -0.0333741
@everywhere ΔQs = collect(range(0, stop=50, length=25)) # amu^0.5 Å
@everywhere ΔEs = collect(range(0, stop=2.5, length=10)) # eV. For solar materials, bandgap rarely exceeds 2eV

# initialise arrays
@everywhere ccArray = SharedArray{Float64}(length(ΔQs), length(ΔEs))

# Parallelise over the biggest loop
@sync @distributed for (qi,ΔQ) in collect(enumerate(ΔQs))
    for (ei,ΔE) in enumerate(ΔEs)
        poti, potf = fitMorseParams(a_i, a_f, b_i, b_f, ΔQ, ΔE)
        capt_coeff, barrier_height = getMorseCapture(poti, potf)

        for (i,cc) in enumerate(capt_coeff) # temperature dependence is stored in an array
            ccArray[qi, ei, i] = cc
        end

    end
end

npzwrite("ccArray.npz", ccArray)


text:
using JLD, GibbsTypePriors, DataFramesMeta, RCall, Optim, OptimTestProblems, StatsBase

include("/Users/dariabystrova/Documents/GitHub/approximatingBNPpriors/scripts_for_figures/common_functions.jl")
include("/Users/dariabystrova/Documents/GitHub/approximatingBNPpriors/scripts_for_figures/FK_sampling_functions.jl")
include("/Users/dariabystrova/Documents/GitHub/approximatingBNPpriors/scripts_for_figures/SB_sampling_functions.jl")

load("/Users/dariabystrova/Documents/GitHub/approximatingBNPpriors/saves_for_figures/figure_3.jld")

function approximation_prior_distribution_precomp(beta,sigma,N,Nt,sigma_arr,df)
    i = findall(x->x==sigma, sigma_arr)
    Pkn_numeric_ = df[i[1]].Pkn_numeric
    Pkn_order2_ = df[i[1]].Pkn_order2
    Pkn_FK_ =  Pkn_NGG_FK(N, beta, sigma, Nt; runs=2*10^2)
    Pkn_SB_  = Pkn_NGG_SB_1(N,beta,sigma,Nt; runs=2*10^2)
    Pkn_NGGMult = Pkn_NGGM_precomp.(1:N,N,Nt,beta,sigma, [Pkn_numeric_])
        df= DataFrame(Pkn_numeric = Pkn_numeric_,
                  Pkn_order2 = Pkn_order2_,
                  Pkn_NGGM = Pkn_NGGMult,
                  Pkn_FK = Pkn_FK_,
                  Pkn_SB = Pkn_SB_)
       return df
end

# truncation 1000
DF_all_100=DF_100[1]
n=100
β= 1.0
ntr=1000
sigma_vec= [0.25,0.75]
DF_1_100_1000 = map(x ->approximation_prior_distribution_precomp(β,x,n,ntr,sigma_vec,  DF_all_100),sigma_vec)

DF_all_10_100_1000=DF_100[2]

n=100
β= 10.0
ntr=1000
sigma_vec= [0.25,0.75]
DF_10_1000_1000 = map(x ->approximation_prior_distribution_precomp(β,x,n,ntr,sigma_vec, DF_all_10_100_1000),sigma_vec)

DF_100_1000 = [DF_1_100_1000,DF_10_1000_1000]

save("/Users/dariabystrova/Documents/GitHub/approximatingBNPpriors/saves_for_figures/figure_3.jld", "DF_100_1000" ,DF_100_1000)

max_stars_repo_name: konkam/approximatingBNPpriors

max_issues_repo_name: konkam/approximatingBNPpriors

max_forks_repo_name: konkam/approximatingBNPpriors


text:
# using TablesDemo
# tbl = Table(
#     A = NullableArray(rand(10)),
#     B = NullableArray(rand(10))
# )

# @with df1(i), df2(j), df3(k), df4(h) do
#     filter(i.A > .5, i.B == j.B, j.C < .5)
#     filter(i.A  > .6)
# end
#
# @with df1(i), df2(j), df3(k), df4(h) do
#     filter(i.A > .5, i.B == j.B, j.C < .5)
#     filter(i.A * j.B > .6)
# end
#
# @with df1(i), df2(j), df3(k), df4(h) do
#     filter(i.A > .5, i.B == j.B, j.C < .5)
#     filter(i.C < .5, i.D == k.D, j.D == "dplyr", k.D == h.D, k.E > .5, h.F == "pandas")
# end
#
# # TODO: make the following raise a warning because of unjoined i path
# @with df1(i), df2(j), df3(k), df4(h) do
#     filter(i.A > .5, i.B == j.B, j.C < .5)
#     filter(i.C < .5, j.D == "dplyr", k.D == h.D, k.E > .5, h.F == "pandas")
# end
#
# # NOTE: should also raise a warning, but the i path gets joined
# @with df1(i), df2(j), df3(k), df4(h) do
#     filter(i.A > .5, i.B == j.B, j.C < .5)
#     filter(i.C < .5, j.D == "dplyr", k.D == h.D, k.E > .5, h.F == "pandas")
#     join(i.D == k.D)
# end
#
# # NOTE: should also raise a warning, but the i path gets joined
# @with df1(i), df2(j), df3(k), df4(h) do
#     filter(i.A > .5, i.B == j.B, j.C < .5)
#     filter(i.C < .5, j.D == "dplyr", k.D == h.D, k.E > .5, h.F == "pandas")
#     join(i.D == k.D)
#     groupby(f(i.A) < .5, k.D, g(j.B * k.C))
# end
#
# # NOTE: currently errors, but should probably just raise a warning if the above
# #       only raise warnings
# @with df1(i), df2(j) do
#     filter(i.A > .5, j.B < .5)
# end
#
# # NOTE: The following errors because our join algorithm doesn't yet support this
# #       type of join
# @with df1(i), df2(j) do
#     filter(i.A * j.B == .5)
# end


text:
using Documenter, Akagera

makedocs(
    modules = [Akagera],
    clean = false,
    format = :html,
    sitename = "Akagera.jl",
    authors = "Colaholic",
    pages = [
        "Home" => "index.md",
        "Manual" => "manual/tutorial.md",
        "Library" => Any[
            "lib/animator.md",
            "lib/animecontainer.md"
        ]
    ],
    html_canonical = "https://lcolaholicl.github.io/Akagera.j/stable"
)

deploydocs(
    julia = "nightly",
    repo = "github.com/lcolaholicl/Akagera.jl.git",
    target = "build",
    deps = nothing,
    make = nothing,
)


text:
# A test for verifiying existing Verificatum proof

using Test
import ShuffleProofs: Simulator, VInit, VPoSCommit, PoSChallenge, verify, load_verificatum_simulator
import ShuffleProofs: interpret # For additional verification
import CryptoGroups: value

DEMO_DIR = "$(@__DIR__)/../ref/demo/"

simulator = load_verificatum_simulator(DEMO_DIR)

# I may also add a test on the group parameter as the test set must be compatible, for actual testing. Unless v1.rho is accepted as an ultimate truth.

(; verifier, proposition, proof) = simulator

v1 = VInit(verifier, proposition)

@test bytes2hex(v1.ρ) == "15e6c97600bbe30125cbc08598dcde01a769c15c8afe08fe5b7f5542533159e9"

h_str = "(1da949a3dfbeb316e9b225bc7d75b78d0ddd5e44fc382e74f3de95ad10eac798c4cc7be7e57d3afb259964c90fe7eb7e28a7673228d6b35a789dabd0d8351675,2937c1c4771b70c8b3dc935681aa8cef45ed24cf0c74cd2f9599ea5876850936168c5a092270d6396e634b9e46ab59836f509d0a68a65edc1426a87fd157798f,3767a5e108ecc067c31cd8bf544bcebfa3e3002f2af499ad3568e6fdb2775f4147bcf9485aeea3180b81aad365e3f4375c280941fdae10812bf1ba445030ab00,5c83d2d4f9cf3b3c2267788dd95a14740964e89f177690d06c43adfd137a101698c6bdc7ea9565fd0b18b3cfa89a2d5ea860de3912af4ffbae2c1f722912f6b9,2c453b082a201f3410d0b2906e7f2998a2c50d84f8eb0af017bf76124424bd385c15446eaad77b3ef1831798093f688331475c754f9e737d1485d80f0ef8289b,534897b93e335b0de44f3426aa6597170857f610ce0e4ff8af8efc5010ab5dc205ec53da9759e0c5ad0d2fdbf3d116e1ad7a94629c2ee331e8ceb29417983c50,7d09ab7d0704e68376e933ccfbbaa0a2e8b10a270ce72a5add597ae66e692bd930b019cc9be30b25e859dd6ba5e3bd74a872588b1e14885bacaeca3b254cc86a,33ff08f3aae9132accec73805ec2cd98ce871779369d69d135a7e1fb75b653d415480be64116feda3176dc83b2d54cf8240f8c6f1d85168081efb4f013106cdb,921ce5123ccb3b891f9e1f314d84b8ca827c44dc2027dd4fd8272189ba076eba7c2cfe7e8f8a8915b263fc72232e5d5f193f15ff6aece5b9c55f4ca9c1887fcf,410494b95d3e453e46d0b8915765f2316fcf4db7d7eff0349fe674a6498d3aaa2c3bae2b4e3c7ec1a5d5fd90d88a1e9886914f4b8d039cd470d69642b0203b73)"
𝐡′ = interpret.(BigInt, hex2bytes.(split(h_str[2:end-1], ",")))

@test 𝐡′ == value.(v1.𝐡)

verify(proposition, proof, verifier)

### Let's now test the primitives
import ShuffleProofs: VInit, VPermCommit, VPoSCommit, PoSChallenge

v1 = VInit(verifier, proposition)

(; μ) = proof
v2 = VPermCommit(v1, μ)

(; τ) = proof
v3 = VPoSCommit(v2, τ)

chg = PoSChallenge(v3)

@test verify(proposition, proof, chg)

import ShuffleProofs: PoSProof

hproof = PoSProof(proof)

@test verify(proposition, hproof, chg)

# The full verification of converted proof
@test verify(proposition, hproof, verifier)


text:
module Mongoc
using MongoC_jll

import Base.UUID
using Dates, DecFP, Serialization

#
# utility functions for date conversion
#

# offsets an additional year from UNIXEPOCH in milliseconds.
const ISODATE_OFFSET = Dates.UNIXEPOCH + 24 * 60 * 60 * 1000 * 365
isodate2datetime(millis::Int64) = Dates.epochms2datetime(millis + ISODATE_OFFSET)
datetime2isodate(dt::DateTime) = Dates.datetime2epochms(dt) - ISODATE_OFFSET

include("bson.jl")
include("types.jl")
include("c_api.jl")
include("client.jl")
include("clientpool.jl")
include("database.jl")
include("collection.jl")
include("session.jl")
include("streams.jl")
include("gridfs.jl")

function __init__()
    mongoc_init()
    atexit(mongoc_cleanup)
end

end # module Mongoc


text:
using LinearAlgebra
using KrylovKit
using OMEinsum
using IterTools
"""
tensor order graph: from left to right, top to bottom.
```
a ────┬──── c    a──────┬──────b
│     b     │    │      │      │
├─ d ─┼─ e ─┤    │      c      │
│     g     │    │      │      │
f ────┴──── h    d──────┴──────e
```
"""

"""
    λ, FL = leftenv(Au, Ad, M, FL = _arraytype(Au)(rand(eltype(Au), size(Au,1), size(M,1), size(Au,1))); kwargs...)

Compute the left environment tensor for MPS `AL` and MPO `M`, by finding the left fixed point
of `Au - M - Ad` contracted Aung the physical dimension.
```
┌──  Au─       ┌──       a ────┬──── c
│    │         │         │     b     │
FL ─ M ─  = λL FL─       ├─ d ─┼─ e ─┤
│    │         │         │     g     │
┕──  Ad─       ┕──       f ────┴──── h
```
"""
function leftenv(Au, Ad, M, FL = _arraytype(Au)(rand(eltype(Au), size(Au,1), size(M,1), size(Ad,1))); kwargs...)
    λs, FLs, info = eigsolve(FL -> ein"((adf,abc),dgeb),fgh -> ceh"(FL,Au,M,Ad), FL, 1, :LM; ishermitian = false, kwargs...)
    if length(λs) > 1 && norm(abs(λs[1]) - abs(λs[2])) < 1e-12
        @show λs
        if real(λs[1]) > 0
            return λs[1], FLs[1]
        else
            return λs[2], FLs[2]
        end
    end
    return λs[1], FLs[1]
end

"""
    λ, FR = rightenv(Au, Ad, M, FR = _arraytype(Au)(randn(eltype(Au), size(Au,1), size(M,3), size(Au,1))); kwargs...)

Compute the right environment tensor for MPS `AR` and MPO `M`, by finding the right fixed point
of `Au - M - Ad` contracted Aung the physical dimension.
```
 ─ Au ──┐         ──┐      a ────┬──── c
    │   │           │      │     b     │
 ─  M ──FR   = λR ──FR     ├─ d ─┼─ e ─┤
    │   │           │      │     g     │
 ─ Ad ──┘         ──┘      f ────┴──── h
```
"""
function rightenv(Au, Ad, M, FR = _arraytype(Au)(randn(eltype(Au), size(Au,1), size(M,3), size(Ad,1))); kwargs...)
    Au = permutedims(Au,(3,2,1))
    Ad = permutedims(Ad,(3,2,1))
    ML = permutedims(M,(3,2,1,4))
    return leftenv(Au, Ad, ML, FR; kwargs...)
end

"""
    λ, FL = norm_FL(Au, Ad, FL; kwargs...)

Compute the left environment tensor for normalization, by finding the left fixed point
of `Au - Ad` contracted Aung the physical dimension.
```
┌── Au─      ┌──         a──────┬──────b
FL  │  =  λL FL                 │
┕── Ad─      ┕──                c
                                │
                         d──────┴──────e
```
"""
function norm_FL(Au, Ad, FL = _arraytype(Au)(rand(eltype(Au), size(Au,1), size(Ad,1))); kwargs...)
    λs, FLs, info = eigsolve(FL -> ein"(ad,acb),dce -> be"(FL,Au,Ad), FL, 1, :LM; ishermitian = false, kwargs...)
    if length(λs) > 1 && norm(abs(λs[1]) - abs(λs[2])) < 1e-12
        @show λs
        if real(λs[1]) > 0
            return λs[1], FLs[1]
        else
            return λs[2], FLs[2]
        end
    end
    return λs[1], FLs[1]
end

"""
    λ, FR = norm_FR(Au, Ad, FR; kwargs...)

Compute the right environment tensor for normalization, by finding the right fixed point
of `Au - Ad` contracted Aung the physical dimension.
```
 ─ AR──┐       ──┐       a──────┬──────b
   │   FR  = λR  FR             │
 ─ AR──┘       ──┘              c
                                │
                         d──────┴──────e
```
"""
function norm_FR(Au, Ad, FR = _arraytype(Au)(randn(eltype(Au), size(Au,3), size(Ad,3))); kwargs...)
    Au = permutedims(Au,(3,2,1))
    Ad = permutedims(Ad,(3,2,1))
    return norm_FL(Au, Ad, FR; kwargs...)
end


text:
# P320 E5 McGrawHill 2º Bachillerato
const c = 3e8                   # m/s velocidad de la luz en el vacío
const h = 6.63e-34              # J·s
const Me = 9.11e-31             # Kg

We_eV = 3.0                     # eV
v = 1.00e6                      # m/s
eCinéticaC = 6.89e-19           # J Energía Cinética del apartado C

frecuencia = NaN                # Hz
longitudDeOnda = NaN            # m
longitudDeOndaC = NaN           # m Longitud de onda en el apartado C

# Frecuencia
function f(We, m, v)
    return (1/h)*(We+Ec(m,v))
end

# Energía cinética
function Ec(m, v)
    return 0.5m*v^2
end

# Longitud de onda asociada a los electrones de De Broglie
function l(m, v)
    return h/(m*v)
end

function main()
    global frecuencia, longitudDeOnda, longitudDeOndaC
    frecuencia = f(We_eV*1.6e-19, Me, v)    # Apartado A
    longitudDeOnda = l(Me, v)               # Apartado B

    energía2 = We_eV*1.6e-19 + eCinéticaC   # Apartado C
    longitudDeOndaC = (h*c)/energía2

    println(frecuencia, " Hz")
    println(longitudDeOnda, " m")
    println(longitudDeOndaC, " m")

end

main()

max_stars_repo_name: profesors/physics

max_issues_repo_name: profesors/physics

max_forks_repo_name: profesors/physics


text:
Gm, Gn = 100, 100;
Gcolptr = [1, 4, 8, 13, 18, 23, 28, 33, 38, 43, 48, 53, 58, 63, 68, 73, 78, 83, 88, 93, 98, 103, 108, 113, 118, 123, 128, 133, 138, 143, 148, 153, 158, 163, 168, 173, 178, 183, 188, 193, 198, 203, 208, 213, 218, 223, 228, 233, 238, 243, 248, 253, 258, 263, 268, 273, 278, 283, 288, 293, 298, 303, 308, 313, 318, 323, 328, 333, 338, 343, 348, 353, 358, 363, 368, 373, 378, 383, 388, 393, 398, 403, 408, 413, 418, 423, 428, 433, 438, 443, 448, 453, 458, 463, 468, 473, 478, 483, 488, 492, 495];
Growval = [1, 2, 3, 1, 2, 3, 4, 1, 2, 3, 4, 5, 2, 3, 4, 5, 6, 3, 4, 5, 6, 7, 4, 5, 6, 7, 8, 5, 6, 7, 8, 9, 6, 7, 8, 9, 10, 7, 8, 9, 10, 11, 8, 9, 10, 11, 12, 9, 10, 11, 12, 13, 10, 11, 12, 13, 14, 11, 12, 13, 14, 15, 12, 13, 14, 15, 16, 13, 14, 15, 16, 17, 14, 15, 16, 17, 18, 15, 16, 17, 18, 19, 16, 17, 18, 19, 20, 17, 18, 19, 20, 21, 18, 19, 20, 21, 22, 19, 20, 21, 22, 23, 20, 21, 22, 23, 24, 21, 22, 23, 24, 25, 22, 23, 24, 25, 26, 23, 24, 25, 26, 27, 24, 25, 26, 27, 28, 25, 26, 27, 28, 29, 26, 27, 28, 29, 30, 27, 28, 29, 30, 31, 28, 29, 30, 31, 32, 29, 30, 31, 32, 33, 30, 31, 32, 33, 34, 31, 32, 33, 34, 35, 32, 33, 34, 35, 36, 33, 34, 35, 36, 37, 34, 35, 36, 37, 38, 35, 36, 37, 38, 39, 36, 37, 38, 39, 40, 37, 38, 39, 40, 41, 38, 39, 40, 41, 42, 39, 40, 41, 42, 43, 40, 41, 42, 43, 44, 41, 42, 43, 44, 45, 42, 43, 44, 45, 46, 43, 44, 45, 46, 47, 44, 45, 46, 47, 48, 45, 46, 47, 48, 49, 46, 47, 48, 49, 50, 47, 48, 49, 50, 51, 48, 49, 50, 51, 52, 49, 50, 51, 52, 53, 50, 51, 52, 53, 54, 51, 52, 53, 54, 55, 52, 53, 54, 55, 56, 53, 54, 55, 56, 57, 54, 55, 56, 57, 58, 55, 56, 57, 58, 59, 56, 57, 58, 59, 60, 57, 58, 59, 60, 61, 58, 59, 60, 61, 62, 59, 60, 61, 62, 63, 60, 61, 62, 63, 64, 61, 62, 63, 64, 65, 62, 63, 64, 65, 66, 63, 64, 65, 66, 67, 64, 65, 66, 67, 68, 65, 66, 67, 68, 69, 66, 67, 68, 69, 70, 67, 68, 69, 70, 71, 68, 69, 70, 71, 72, 69, 70, 71, 72, 73, 70, 71, 72, 73, 74, 71, 72, 73, 74, 75, 72, 73, 74, 75, 76, 73, 74, 75, 76, 77, 74, 75, 76, 77, 78, 75, 76, 77, 78, 79, 76, 77, 78, 79, 80, 77, 78, 79, 80, 81, 78, 79, 80, 81, 82, 79, 80, 81, 82, 83, 80, 81, 82, 83, 84, 81, 82, 83, 84, 85, 82, 83, 84, 85, 86, 83, 84, 85, 86, 87, 84, 85, 86, 87, 88, 85, 86, 87, 88, 89, 86, 87, 88, 89, 90, 87, 88, 89, 90, 91, 88, 89, 90, 91, 92, 89, 90, 91, 92, 93, 90, 91, 92, 93, 94, 91, 92, 93, 94, 95, 92, 93, 94, 95, 96, 93, 94, 95, 96, 97, 94, 95, 96, 97, 98, 95, 96, 97, 98, 99, 96, 97, 98, 99, 100, 97, 98, 99, 100, 98, 99, 100];
Gnzval = [-0.22222222222222232, 0.33333333333333326, -0.3333333333333333, 0.7777777777777777, 2.220446049250313e-16, 0.33333333333333326, -0.3333333333333333, -0.4444444444444444, 0.33333333333333326, 2.220446049250313e-16, 0.33333333333333326, -0.3333333333333333, -0.3333333333333333, 0.33333333333333326, 2.220446049250313e-16, 0.33333333333333326, -0.3333333333333333, -0.3333333333333333, 0.33333333333333326, 2.220446049250313e-16, 0.33333333333333326, -0.3333333333333333, -0.3333333333333333, 0.33333333333333326, 2.220446049250313e-16, 0.33333333333333326, -0.3333333333333333, -0.3333333333333333, 0.33333333333333326, 2.220446049250313e-16, 0.33333333333333326, -0.3333333333333333, -0.3333333333333333, 0.33333333333333326, 2.220446049250313e-16, 0.33333333333333326, -0.3333333333333333, -0.3333333333333333, 0.33333333333333326, 2.220446049250313e-16, 0.33333333333333326, -0.3333333333333333, -0.3333333333333333, 0.33333333333333326, 2.220446049250313e-16, 0.33333333333333326, -0.3333333333333333, -0.3333333333333333, 0.33333333333333326, 2.220446049250313e-16, 0.33333333333333326, -0.3333333333333333, -0.3333333333333333, 0.33333333333333326, 2.220446049250313e-16, 0.33333333333333326, -0.3333333333333333, -0.3333333333333333, 0.33333333333333326, 2.220446049250313e-16, 0.33333333333333326, -0.3333333333333333, -0.3333333333333333, 0.33333333333333326, 2.220446049250313e-16, 0.33333333333333326, -0.3333333333333333, -0.3333333333333333, 0.33333333333333326, 2.220446049250313e-16, 0.33333333333333326, -0.3333333333333333, -0.3333333333333333, 0.33333333333333326, 2.220446049250313e-16, 0.33333333333333326, -0.3333333333333333, -0.3333333333333333, 0.33333333333333326, 2.220446049250313e-16, 0.33333333333333326, -0.3333333333333333, -0.3333333333333333, 0.33333333333333326, 2.220446049250313e-16, 0.33333333333333326, -0.3333333333333333, -0.3333333333333333, 0.33333333333333326, 2.220446049250313e-16, 0.33333333333333326, -0.3333333333333333, -0.3333333333333333, 0.33333333333333326, 2.220446049250313e-16, 0.33333333333333326, -0.3333333333333333, -0.3333333333333333, 0.33333333333333326, 2.220446049250313e-16, 0.33333333333333326, -0.3333333333333333, -0.3333333333333333, 0.33333333333333326, 2.220446049250313e-16, 0.33333333333333326, -0.3333333333333333, -0.3333333333333333, 0.33333333333333326, 2.220446049250313e-16, 0.33333333333333326, -0.3333333333333333, -0.3333333333333333, 0.33333333333333326, 2.220446049250313e-16, 0.33333333333333326, -0.3333333333333333, -0.3333333333333333, 0.33333333333333326, 2.220446049250313e-16, 0.33333333333333326, -0.3333333333333333, -0.3333333333333333, 0.33333333333333326, 2.220446049250313e-16, 0.33333333333333326, -0.3333333333333333, -0.3333333333333333, 0.33333333333333326, 2.220446049250313e-16, 0.33333333333333326, -0.3333333333333333, -0.3333333333333333, 0.33333333333333326, 2.220446049250313e-16, 0.33333333333333326, -0.3333333333333333, -0.3333333333333333, 0.33333333333333326, 2.220446049250313e-16, 0.33333333333333326, -0.3333333333333333, -0.3333333333333333, 0.33333333333333326, 2.220446049250313e-16, 0.33333333333333326, -0.3333333333333333, -0.3333333333333333, 0.33333333333333326, 2.220446049250313e-16, 0.33333333333333326, -0.3333333333333333, -0.3333333333333333, 0.33333333333333326, 2.220446049250313e-16, 0.33333333333333326, -0.3333333333333333, -0.3333333333333333, 0.33333333333333326, 2.220446049250313e-16, 0.33333333333333326, -0.3333333333333333, -0.3333333333333333, 0.33333333333333326, 2.220446049250313e-16, 0.33333333333333326, -0.3333333333333333, -0.3333333333333333, 0.33333333333333326, 2.220446049250313e-16, 0.33333333333333326, -0.3333333333333333, -0.3333333333333333, 0.33333333333333326, 2.220446049250313e-16, 0.33333333333333326, -0.3333333333333333, -0.3333333333333333, 0.33333333333333326, 2.220446049250313e-16, 0.33333333333333326, -0.3333333333333333, -0.3333333333333333, 0.33333333333333326, 2.220446049250313e-16, 0.33333333333333326, -0.3333333333333333, -0.3333333333333333, 0.33333333333333326, 2.220446049250313e-16, 0.33333333333333326, -0.3333333333333333, -0.3333333333333333, 0.33333333333333326, 2.220446049250313e-16, 0.33333333333333326, -0.3333333333333333, -0.3333333333333333, 0.33333333333333326, 2.220446049250313e-16, 0.33333333333333326, -0.3333333333333333, -0.3333333333333333, 0.33333333333333326, 2.220446049250313e-16, 0.33333333333333326, -0.3333333333333333, -0.3333333333333333, 0.33333333333333326, 2.220446049250313e-16, 0.33333333333333326, -0.3333333333333333, -0.3333333333333333, 0.33333333333333326, 2.220446049250313e-16, 0.33333333333333326, -0.3333333333333333, -0.3333333333333333, 0.33333333333333326, 2.220446049250313e-16, 0.33333333333333326, -0.3333333333333333, -0.3333333333333333, 0.33333333333333326, 2.220446049250313e-16, 0.33333333333333326, -0.3333333333333333, -0.3333333333333333, 0.33333333333333326, 2.220446049250313e-16, 0.33333333333333326, -0.3333333333333333, -0.3333333333333333, 0.33333333333333326, 2.220446049250313e-16, 0.33333333333333326, -0.3333333333333333, -0.3333333333333333, 0.33333333333333326, 2.220446049250313e-16, 0.33333333333333326, -0.3333333333333333, -0.3333333333333333, 0.33333333333333326, 2.220446049250313e-16, 0.33333333333333326, -0.3333333333333333, -0.3333333333333333, 0.33333333333333326, 2.220446049250313e-16, 0.33333333333333326, -0.3333333333333333, -0.3333333333333333, 0.33333333333333326, 2.220446049250313e-16, 0.33333333333333326, -0.3333333333333333, -0.3333333333333333, 0.33333333333333326, 2.220446049250313e-16, 0.33333333333333326, -0.3333333333333333, -0.3333333333333333, 0.33333333333333326, 2.220446049250313e-16, 0.33333333333333326, -0.3333333333333333, -0.3333333333333333, 0.33333333333333326, 2.220446049250313e-16, 0.33333333333333326, -0.3333333333333333, -0.3333333333333333, 0.33333333333333326, 2.220446049250313e-16, 0.33333333333333326, -0.3333333333333333, -0.3333333333333333, 0.33333333333333326, 2.220446049250313e-16, 0.33333333333333326, -0.3333333333333333, -0.3333333333333333, 0.33333333333333326, 2.220446049250313e-16, 0.33333333333333326, -0.3333333333333333, -0.3333333333333333, 0.33333333333333326, 2.220446049250313e-16, 0.33333333333333326, -0.3333333333333333, -0.3333333333333333, 0.33333333333333326, 2.220446049250313e-16, 0.33333333333333326, -0.3333333333333333, -0.3333333333333333, 0.33333333333333326, 2.220446049250313e-16, 0.33333333333333326, -0.3333333333333333, -0.3333333333333333, 0.33333333333333326, 2.220446049250313e-16, 0.33333333333333326, -0.3333333333333333, -0.3333333333333333, 0.33333333333333326, 2.220446049250313e-16, 0.33333333333333326, -0.3333333333333333, -0.3333333333333333, 0.33333333333333326, 2.220446049250313e-16, 0.33333333333333326, -0.3333333333333333, -0.3333333333333333, 0.33333333333333326, 2.220446049250313e-16, 0.33333333333333326, -0.3333333333333333, -0.3333333333333333, 0.33333333333333326, 2.220446049250313e-16, 0.33333333333333326, -0.3333333333333333, -0.3333333333333333, 0.33333333333333326, 2.220446049250313e-16, 0.33333333333333326, -0.3333333333333333, -0.3333333333333333, 0.33333333333333326, 2.220446049250313e-16, 0.33333333333333326, -0.3333333333333333, -0.3333333333333333, 0.33333333333333326, 2.220446049250313e-16, 0.33333333333333326, -0.3333333333333333, -0.3333333333333333, 0.33333333333333326, 2.220446049250313e-16, 0.33333333333333326, -0.3333333333333333, -0.3333333333333333, 0.33333333333333326, 2.220446049250313e-16, 0.33333333333333326, -0.3333333333333333, -0.3333333333333333, 0.33333333333333326, 2.220446049250313e-16, 0.33333333333333326, -0.3333333333333333, -0.3333333333333333, 0.33333333333333326, 2.220446049250313e-16, 0.33333333333333326, -0.3333333333333333, -0.3333333333333333, 0.33333333333333326, 2.220446049250313e-16, 0.33333333333333326, -0.3333333333333333, -0.3333333333333333, 0.33333333333333326, 2.220446049250313e-16, 0.33333333333333326, -0.3333333333333333, -0.3333333333333333, 0.33333333333333326, 2.220446049250313e-16, 0.33333333333333326, -0.3333333333333333, -0.3333333333333333, 0.33333333333333326, 2.220446049250313e-16, 0.33333333333333326, -0.3333333333333333, -0.3333333333333333, 0.33333333333333326, 2.220446049250313e-16, 0.33333333333333326, -0.3333333333333333, -0.3333333333333333, 0.33333333333333326, 2.220446049250313e-16, 0.33333333333333326, -0.3333333333333333, -0.3333333333333333, 0.33333333333333326, 2.220446049250313e-16, 0.33333333333333326, -0.3333333333333333, -0.3333333333333333, 0.33333333333333326, 2.220446049250313e-16, 0.33333333333333326, -0.3333333333333333, -0.3333333333333333, 0.33333333333333326, 2.220446049250313e-16, 0.33333333333333326, -0.3333333333333333, -0.3333333333333333, 0.33333333333333326, 2.220446049250313e-16, 0.33333333333333326, -0.3333333333333333, -0.3333333333333333, 0.33333333333333326, 2.220446049250313e-16, 0.33333333333333326, -0.3333333333333333, -0.3333333333333333, 0.33333333333333326, 2.220446049250313e-16, 0.33333333333333326, -0.3333333333333333, -0.3333333333333333, 0.33333333333333326, 2.220446049250313e-16, 0.33333333333333326, -0.3333333333333333, -0.3333333333333333, 0.33333333333333326, 2.220446049250313e-16, 0.33333333333333326, -0.3333333333333333, -0.3333333333333333, 0.33333333333333326, 2.220446049250313e-16, 0.33333333333333326, -0.3333333333333333, -0.3333333333333333, 0.33333333333333326, 2.220446049250313e-16, 0.33333333333333326, -0.3333333333333333, -0.3333333333333333, 0.33333333333333326, 2.220446049250313e-16, 0.33333333333333326, -0.3333333333333333, -0.3333333333333333, 0.33333333333333326, 2.220446049250313e-16, 0.33333333333333326, -0.3333333333333333, -0.3333333333333333, 0.33333333333333326, 2.220446049250313e-16, 0.33333333333333326, -0.3333333333333333, -0.3333333333333333, 0.33333333333333326, 2.220446049250313e-16, 0.33333333333333326, -0.3333333333333333, -0.3333333333333333, 0.33333333333333326, 2.220446049250313e-16, 0.33333333333333326, -0.3333333333333333, -0.3333333333333333, 0.33333333333333326, 2.220446049250313e-16, 0.33333333333333326, -0.3333333333333333, -0.3333333333333333, 0.33333333333333326, 2.220446049250313e-16, 0.33333333333333326, -0.3333333333333333, -0.3333333333333333, 0.33333333333333326, 2.220446049250313e-16, 0.33333333333333326, -0.3333333333333333, -0.3333333333333333, 0.33333333333333326, 2.220446049250313e-16, 0.33333333333333326, -0.4444444444444444, -0.3333333333333333, 0.33333333333333326, 2.220446049250313e-16, 0.7777777777777777, -0.3333333333333333, 0.33333333333333326, -0.22222222222222232];
G = SparseMatrixCSC(Gm, Gn, Gcolptr, Growval, Gnzval);


text:
module NearlyNewton

# We use often use the LinearAlgebra functions dot and norm for operations rela-
# ted to assessing angles between vectors, size of vectors and so on. I is mainly
# used to get gradient descent for free out of Newton's method.
using LinearAlgebra: dot, I, norm, mul!,
                     cholesky, ldiv!, rmul!,
                     UniformScaling, Symmetric,
                     factorize, eigen, Hermitian,
                     diag, # for trust region diagonal manipulation
                     opnorm # for NWI safe guards

#using TRS

# make this struct that has scheme and approx
abstract type QuasiNewton{T1} end
struct Newton{T1} <: QuasiNewton{T1}
   approx::T1
end
export Newton

struct OptOptions{T1, T2}
    c::T1
    g_tol::T1
    maxiter::T2
    show_trace::Bool
end

OptOptions(; c=1e-4, g_tol=1e-8, maxiter=10^4, show_trace=false) =
OptOptions(c, g_tol, maxiter, show_trace)

# Include the actual functions that expose the functionality in this package.
include("hessian_object.jl")

include("quasinewton/update_qn.jl")
include("minimize.jl")
export minimize, minimize!, OptOptions
export backtracking, BackTracking
export NWI
export InverseApprox, DirectApprox

include("nlsolve.jl")
export nlsolve, nlsolve!

struct MinimizationProblem{Tobj, Tcon}
    objective::Tobj
    constraints::Tcon
end
struct MaximizationProblem{Tobj, Tcon}
    objective::Tobj
    constraints::Tcon
end
struct Objective{T, InformationOrder, Inplace}
    func::T
end

abstract type ObjectiveOrder end
struct OrderZero <: ObjectiveOrder end
struct OrderOne <: ObjectiveOrder end
struct OrderTwo <: ObjectiveOrder end

function Objective(order=nothing; f=nothing, g=nothing,
                                  fg=nothing, h=nothing,
                                  fgh=nothing, inplace=true)

    if order == OrderZero && !(f==nothing)
        return f
    end
end

include("./quasinewton/find_direction.jl")
include("./quasinewton/SR1.jl")
include("./quasinewton/formulae.jl")
include("./quasinewton/gradientdescent.jl")
include("./quasinewton/BFGS.jl")
include("./quasinewton/DFP.jl")
# Export algos
export BFGS, SR1, DFP, GradientDescent

end # module


text:
#### thermodynamics

export new_thermo_state_anelastic, recover_thermo_state_anelastic

"""
    new_thermo_state_anelastic(atmos::AtmosModel, state::Vars, aux::Vars)

Create a new thermodynamic state, based on the `state`, and _not_
the `aux` state.

!!! note
    This method calls the iterative saturation adjustment
    procedure for EquilMoist models.
"""
new_thermo_state_anelastic(atmos::AtmosModel, state::Vars, aux::Vars) =
    new_thermo_state_anelastic(
        atmos,
        energy_model(atmos),
        moisture_model(atmos),
        state,
        aux,
    )

"""
    recover_thermo_state_anelastic(atmos::AtmosModel, state::Vars, aux::Vars)

An atmospheric thermodynamic state.

!!! warn
    For now, we are directly calling new_thermo_state_anelastic to avoid
    inconsistent aux states in kernels where the aux states are
    out of sync with the boundary state.

# TODO: Define/call `recover_thermo_state_anelastic` when it's safely implemented
  (see https://github.com/CliMA/ClimateMachine.jl/issues/1648)
"""
recover_thermo_state_anelastic(atmos::AtmosModel, state::Vars, aux::Vars) =
    new_thermo_state_anelastic(
        atmos,
        energy_model(atmos),
        moisture_model(atmos),
        state,
        aux,
    )

function new_thermo_state_anelastic(
    atmos::AtmosModel,
    energy::TotalEnergyModel,
    moist::DryModel,
    state::Vars,
    aux::Vars,
)
    param_set = parameter_set(atmos)
    e_int = internal_energy(atmos, state, aux)
    p = aux.ref_state.p
    return PhaseDry_pe(param_set, p, e_int)
end

function new_thermo_state_anelastic(
    atmos::AtmosModel,
    energy::TotalEnergyModel,
    moist::EquilMoist,
    state::Vars,
    aux::Vars,
)
    param_set = parameter_set(atmos)
    e_int = internal_energy(atmos, state, aux)
    p = aux.ref_state.p
    ρ = density(atmos, state, aux)
    return PhaseEquil_peq(
        param_set,
        p,
        e_int,
        state.moisture.ρq_tot / ρ,
        moist.maxiter,
        moist.tolerance,
    )
end

function new_thermo_state_anelastic(
    atmos::AtmosModel,
    energy::TotalEnergyModel,
    moist::NonEquilMoist,
    state::Vars,
    aux::Vars,
)
    param_set = parameter_set(atmos)
    e_int = internal_energy(atmos, state, aux)
    p = aux.ref_state.p
    ρ = density(atmos, state, aux)
    q = PhasePartition(
        state.moisture.ρq_tot / ρ,
        state.moisture.ρq_liq / ρ,
        state.moisture.ρq_ice / ρ,
    )

    return PhaseNonEquil_peq(param_set, p, e_int, q)
end