Hi Ye!
Happy to see another user of OpenTPS 
You are right that these things are not explained in any documentation yet. We are working in a user-guide to collect all this information. For the moment, let me explain a few things, hopefully that will solve your questions:
Minimum beam energy and Beam model default in OpenTPS: The minimum energy for IBA systems is generally 70 MeV or 100 MeV, depending on the parameterization and calibration of the system. The default BDL in OpenTPS corresponds to a IBA Proteus®PLUS from UPenn. At the time we generated these BDLs (more than 5 years ago), the minimum energy of their system was 100 MeV.
Energy layers in OpenTPS: Energy layers in OpenTPS do not have a minimum or a maximum. They are computed with a raytracing algorithm to get the minimum and maximum WET (Water Equivalent Thickness) to cover the volume selected as target. Then, extra energy layers are added in the distal and proximal edge to be sure that we cover the target. The value by default is to add 1 energy layer both at proximal and distal, but this can be changed. Check the class ProtonPlanDesign :
self.spotSpacing = 5.0
self.layerSpacing = 5.0
self.proximalLayers = 1
self.distalLayers = 1
Note that the variable targetMargin is also there to have a margin around the target to place the spots in a sufficiently large area so that the target will be covered. If you are using robust optimisation with large systematic errors, this margin should probably be adapted and enlarged to cover the target in all your scenarios.
The WET is converted into MeV with the function rangeToEnergy, if values go below the energy in the BDL, a linear interpolation is done. For very small values you will get a warning “warnings.warn('Small proton ranges are used, accuracy of energy computation cannot be guaranteed.')". However, note that it has been tested for small animal cases with small energies and yet the MCsquare achieved quite decent dose calculation. Check lines 95-111 from def initializeBeam in the class BeamInitializer.
In OpenTPS we do not enforce to go discrete and use the energy layers in the BDL, we just use the final interpolated values computed after the process described above. After some clarifications from IBA team, they confirm that the machine is not restricted to deliver only the energies in the BDL, it is indeed almost continuous values that can be achieved (at least less than 0.1 mm resolution in range).
LayerSpacing parameter: The layerSpacing parameter has nothing to do with the minimal energy, this parameter determines how much you will separate the energy layers between them. If you want to use a specific value for your energy (like 102MeV) you better go to the layers and assign the value directly manually (hardcoded). Not sure now what would be the best way, but something like beam.appendLayer(PlanProtonLayer(energy))or overriding in your existing layers can work too.
To remove layers, the best might be to use the function beam.removeLayer()